diff options
Diffstat (limited to 'services')
26 files changed, 729 insertions, 262 deletions
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java index 22efd3718d7a..eb30fdeddd90 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java @@ -118,6 +118,9 @@ class AccessibilityUserState { private int mNonInteractiveUiTimeout = 0; private int mInteractiveUiTimeout = 0; private int mLastSentClientState = -1; + + /** {@code true} if the device config supports magnification area. */ + private final boolean mSupportMagnificationArea; // The magnification mode of default display. private int mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; // The magnification capabilities used to know magnification mode could be switched. @@ -138,6 +141,10 @@ class AccessibilityUserState { private int mSoftKeyboardShowMode = SHOW_MODE_AUTO; boolean isValidMagnificationModeLocked() { + if (!mSupportMagnificationArea + && mMagnificationMode == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) { + return false; + } return (mMagnificationCapabilities & mMagnificationMode) != 0; } @@ -156,6 +163,8 @@ class AccessibilityUserState { R.color.accessibility_focus_highlight_color); mFocusStrokeWidth = mFocusStrokeWidthDefaultValue; mFocusColor = mFocusColorDefaultValue; + mSupportMagnificationArea = mContext.getResources().getBoolean( + R.bool.config_magnification_area); } boolean isHandlingAccessibilityEventsLocked() { diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 76c8d3001158..ffb941415d61 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -132,12 +132,15 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Function; @@ -175,6 +178,11 @@ public class CompanionDeviceManagerService extends SystemService implements Bind private static final String XML_ATTR_TIME_APPROVED = "time_approved"; private static final String XML_FILE_NAME = "companion_device_manager_associations.xml"; + private static DateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + static { + sDateFormat.setTimeZone(TimeZone.getDefault()); + } + private final CompanionDeviceManagerImpl mImpl; private final ConcurrentMap<Integer, AtomicFile> mUidToStorage = new ConcurrentHashMap<>(); private PowerWhitelistManager mPowerWhitelistManager; @@ -619,12 +627,14 @@ public class CompanionDeviceManagerService extends SystemService implements Bind association.getDeviceMacAddress(), association.getPackageName(), association.getDeviceProfile(), - active, /* notifyOnDeviceNearby */ + active /* notifyOnDeviceNearby */, association.getTimeApprovedMs()); } else { return association; } })); + + restartBleScan(); } private void checkCanCallNotificationApi(String callingPackage) throws RemoteException { @@ -680,12 +690,40 @@ public class CompanionDeviceManagerService extends SystemService implements Bind synchronized (mLock) { for (UserInfo user : getAllUsers()) { forEach(mCachedAssociations.get(user.id), a -> { - fout.append(" ") - .append("u").append("" + a.getUserId()).append(": ") - .append(a.getPackageName()).append(" - ") - .append(a.getDeviceMacAddress()).append('\n'); + fout.append(" ").append(a.toString()).append('\n'); }); } + + } + fout.append("Currently Connected Devices:").append('\n'); + for (int i = 0, size = mCurrentlyConnectedDevices.size(); i < size; i++) { + fout.append(" ").append(mCurrentlyConnectedDevices.get(i)).append('\n'); + } + + fout.append("Devices Last Nearby:").append('\n'); + for (int i = 0, size = mDevicesLastNearby.size(); i < size; i++) { + String device = mDevicesLastNearby.keyAt(i); + Date time = mDevicesLastNearby.valueAt(i); + fout.append(" ").append(device).append(" -> ") + .append(sDateFormat.format(time)).append('\n'); + } + + fout.append("Discovery Service State:").append('\n'); + for (int i = 0, size = mServiceConnectors.size(); i < size; i++) { + int userId = mServiceConnectors.keyAt(i); + fout.append(" ") + .append("u").append(Integer.toString(userId)).append(": ") + .append(Objects.toString(mServiceConnectors.valueAt(i))) + .append('\n'); + } + + fout.append("Device Listener Services State:").append('\n'); + for (int i = 0, size = mDeviceListenerServiceConnectors.size(); i < size; i++) { + int userId = mDeviceListenerServiceConnectors.keyAt(i); + fout.append(" ") + .append("u").append(Integer.toString(userId)).append(": ") + .append(Objects.toString(mDeviceListenerServiceConnectors.valueAt(i))) + .append('\n'); } } } @@ -957,6 +995,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind } } + private Set<Association> getAllAssociations( int userId, @Nullable String packageFilter, @Nullable String addressFilter) { return CollectionUtils.filter( @@ -1238,7 +1277,8 @@ public class CompanionDeviceManagerService extends SystemService implements Bind if (DEBUG) { Slog.i(LOG_TAG, "Device " + address + " managed by " + association.getPackageName() - + " disappeared; last seen on " + mDevicesLastNearby.get(address)); + + " disappeared; last seen on " + + sDateFormat.format(mDevicesLastNearby.get(address))); } getDeviceListenerServiceConnector(association).run( diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java index fdda239e7fde..9e126d74b172 100644 --- a/services/core/java/com/android/server/BinderCallsStatsService.java +++ b/services/core/java/com/android/server/BinderCallsStatsService.java @@ -43,6 +43,7 @@ import com.android.internal.os.AppIdToPackageMap; import com.android.internal.os.BackgroundThread; import com.android.internal.os.BinderCallsStats; import com.android.internal.os.BinderInternal; +import com.android.internal.os.BinderLatencyObserver; import com.android.internal.os.CachedDeviceState; import com.android.internal.util.DumpUtils; @@ -124,6 +125,7 @@ public class BinderCallsStatsService extends Binder { /** Listens for flag changes. */ private static class SettingsObserver extends ContentObserver { + // Settings for BinderCallsStats. private static final String SETTINGS_ENABLED_KEY = "enabled"; private static final String SETTINGS_DETAILED_TRACKING_KEY = "detailed_tracking"; private static final String SETTINGS_UPLOAD_DATA_KEY = "upload_data"; @@ -132,6 +134,10 @@ public class BinderCallsStatsService extends Binder { private static final String SETTINGS_TRACK_DIRECT_CALLING_UID_KEY = "track_calling_uid"; private static final String SETTINGS_MAX_CALL_STATS_KEY = "max_call_stats_count"; private static final String SETTINGS_IGNORE_BATTERY_STATUS_KEY = "ignore_battery_status"; + // Settings for BinderLatencyObserver. + private static final String SETTINGS_COLLECT_LATENCY_DATA_KEY = "collect_Latency_data"; + private static final String SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY = + "latency_observer_sampling_interval"; private boolean mEnabled; private final Uri mUri = Settings.Global.getUriFor(Settings.Global.BINDER_CALLS_STATS); @@ -188,6 +194,13 @@ public class BinderCallsStatsService extends Binder { mBinderCallsStats.setIgnoreBatteryStatus( mParser.getBoolean(SETTINGS_IGNORE_BATTERY_STATUS_KEY, BinderCallsStats.DEFAULT_IGNORE_BATTERY_STATUS)); + mBinderCallsStats.setCollectLatencyData( + mParser.getBoolean(SETTINGS_COLLECT_LATENCY_DATA_KEY, + BinderCallsStats.DEFAULT_COLLECT_LATENCY_DATA)); + // Binder latency observer settings. + mBinderCallsStats.getLatencyObserver().setSamplingInterval(mParser.getInt( + SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY, + BinderLatencyObserver.PERIODIC_SAMPLING_INTERVAL_DEFAULT)); final boolean enabled = @@ -206,6 +219,7 @@ public class BinderCallsStatsService extends Binder { mEnabled = enabled; mBinderCallsStats.reset(); mBinderCallsStats.setAddDebugEntries(enabled); + mBinderCallsStats.getLatencyObserver().reset(); } } } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index a4ff230b0678..93eea1169e09 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -135,6 +135,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.function.Predicate; @@ -586,6 +587,45 @@ public final class ActiveServices { return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false; } + boolean hasForegroundServiceNotificationLocked(String pkg, int userId, String channelId) { + final ServiceMap smap = mServiceMap.get(userId); + if (smap != null) { + for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) { + final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i); + if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) { + if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) { + if (DEBUG_FOREGROUND_SERVICE) { + Slog.d(TAG_SERVICE, "Channel u" + userId + "/pkg=" + pkg + + "/channelId=" + channelId + + " has fg service notification"); + } + return true; + } + } + } + } + return false; + } + + void stopForegroundServicesForChannelLocked(String pkg, int userId, String channelId) { + final ServiceMap smap = mServiceMap.get(userId); + if (smap != null) { + for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) { + final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i); + if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) { + if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) { + if (DEBUG_FOREGROUND_SERVICE) { + Slog.d(TAG_SERVICE, "Stopping FGS u" + userId + "/pkg=" + pkg + + "/channelId=" + channelId + + " for conversation channel clear"); + } + stopServiceLocked(sr, false); + } + } + } + } + } + private ServiceMap getServiceMapLocked(int callingUser) { ServiceMap smap = mServiceMap.get(callingUser); if (smap == null) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5ee0e040019c..58ca561c1c83 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -15862,6 +15862,22 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public boolean hasForegroundServiceNotification(String pkg, int userId, + String channelId) { + synchronized (ActivityManagerService.this) { + return mServices.hasForegroundServiceNotificationLocked(pkg, userId, channelId); + } + } + + @Override + public void stopForegroundServicesForChannel(String pkg, int userId, + String channelId) { + synchronized (ActivityManagerService.this) { + mServices.stopForegroundServicesForChannelLocked(pkg, userId, channelId); + } + } + + @Override public void registerProcessObserver(IProcessObserver processObserver) { ActivityManagerService.this.registerProcessObserver(processObserver); } diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index e022e977e02f..52ab4c8f7bd6 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -92,6 +92,7 @@ public class SettingsToPropertiesMapper { DeviceConfig.NAMESPACE_STATSD_NATIVE, DeviceConfig.NAMESPACE_STATSD_NATIVE_BOOT, DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, + DeviceConfig.NAMESPACE_SWCODEC_NATIVE, DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT, }; diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java index 88b26680631e..aa9bbf680004 100644 --- a/services/core/java/com/android/server/display/color/ColorDisplayService.java +++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java @@ -162,7 +162,8 @@ public final class ColorDisplayService extends SystemService { private final ReduceBrightColorsTintController mReduceBrightColorsTintController = new ReduceBrightColorsTintController(); - private final Handler mHandler; + @VisibleForTesting + final Handler mHandler; private final AppSaturationController mAppSaturationController = new AppSaturationController(); @@ -404,13 +405,13 @@ public final class ColorDisplayService extends SystemService { // existing activated state. This ensures consistency of tint across the color mode change. onDisplayColorModeChanged(getColorModeInternal()); + final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); if (mNightDisplayTintController.isAvailable(getContext())) { // Reset the activated state. mNightDisplayTintController.setActivated(null); // Prepare the night display color transformation matrix. - mNightDisplayTintController - .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix()); + mNightDisplayTintController.setUp(getContext(), dtm.needsLinearColorMatrix()); mNightDisplayTintController .setMatrix(mNightDisplayTintController.getColorTemperatureSetting()); @@ -432,8 +433,7 @@ public final class ColorDisplayService extends SystemService { } if (mReduceBrightColorsTintController.isAvailable(getContext())) { - mReduceBrightColorsTintController - .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix()); + mReduceBrightColorsTintController.setUp(getContext(), dtm.needsLinearColorMatrix()); onReduceBrightColorsStrengthLevelChanged(); final boolean reset = resetReduceBrightColors(); if (!reset) { @@ -540,8 +540,8 @@ public final class ColorDisplayService extends SystemService { mDisplayWhiteBalanceTintController.cancelAnimator(); if (mNightDisplayTintController.isAvailable(getContext())) { - mNightDisplayTintController - .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode)); + final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); + mNightDisplayTintController.setUp(getContext(), dtm.needsLinearColorMatrix(mode)); mNightDisplayTintController .setMatrix(mNightDisplayTintController.getColorTemperatureSetting()); } @@ -731,10 +731,11 @@ public final class ColorDisplayService extends SystemService { @VisibleForTesting void updateDisplayWhiteBalanceStatus() { boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated(); + final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled() && !mNightDisplayTintController.isActivated() && !isAccessibilityEnabled() - && DisplayTransformManager.needsLinearColorMatrix()); + && dtm.needsLinearColorMatrix()); boolean activated = mDisplayWhiteBalanceTintController.isActivated(); if (mDisplayWhiteBalanceListener != null && oldActivated != activated) { diff --git a/services/core/java/com/android/server/display/color/DisplayTransformManager.java b/services/core/java/com/android/server/display/color/DisplayTransformManager.java index 5c68c51ad7a3..0dba9e1b0af1 100644 --- a/services/core/java/com/android/server/display/color/DisplayTransformManager.java +++ b/services/core/java/com/android/server/display/color/DisplayTransformManager.java @@ -239,7 +239,7 @@ public class DisplayTransformManager { /** * Return true when the color matrix works in linear space. */ - public static boolean needsLinearColorMatrix() { + public boolean needsLinearColorMatrix() { return SystemProperties.getInt(PERSISTENT_PROPERTY_DISPLAY_COLOR, DISPLAY_COLOR_UNMANAGED) != DISPLAY_COLOR_UNMANAGED; } @@ -247,7 +247,7 @@ public class DisplayTransformManager { /** * Return true when the specified colorMode requires the color matrix to work in linear space. */ - public static boolean needsLinearColorMatrix(int colorMode) { + public boolean needsLinearColorMatrix(int colorMode) { return colorMode != ColorDisplayManager.COLOR_MODE_SATURATED; } diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java index 8405bbe38b12..d422d51d4087 100644 --- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java +++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java @@ -88,7 +88,7 @@ final class ActiveSourceHandler { tv.updateActiveSource(current, "ActiveSourceHandler"); invokeCallback(HdmiControlManager.RESULT_SUCCESS); } else { - tv.startRoutingControl(newActive.physicalAddress, current.physicalAddress, true, + tv.startRoutingControl(newActive.physicalAddress, current.physicalAddress, mCallback); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 8d6bcadb3e2b..0087f180d114 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -370,12 +370,11 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { return; } int newPath = mService.portIdToPath(portId); - startRoutingControl(oldPath, newPath, true, callback); + startRoutingControl(oldPath, newPath, callback); } @ServiceThreadOnly - void startRoutingControl(int oldPath, int newPath, boolean queryDevicePowerStatus, - IHdmiControlCallback callback) { + void startRoutingControl(int oldPath, int newPath, IHdmiControlCallback callback) { assertRunOnServiceThread(); if (oldPath == newPath) { return; @@ -385,7 +384,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { mService.sendCecCommand(routingChange); removeAction(RoutingControlAction.class); addAndStartAction( - new RoutingControlAction(this, newPath, queryDevicePowerStatus, callback)); + new RoutingControlAction(this, newPath, callback)); } @ServiceThreadOnly @@ -554,7 +553,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { if (isTailOfActivePath(path, getActivePath())) { int newPath = mService.portIdToPath(getActivePortId()); setActivePath(newPath); - startRoutingControl(getActivePath(), newPath, false, null); + startRoutingControl(getActivePath(), newPath, null); return true; } return false; @@ -598,7 +597,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { getActiveSource().invalidate(); removeAction(RoutingControlAction.class); int newPath = HdmiUtils.twoBytesToInt(params, 2); - addAndStartAction(new RoutingControlAction(this, newPath, true, null)); + addAndStartAction(new RoutingControlAction(this, newPath, null)); } return true; } @@ -1143,7 +1142,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // Seq #23 if (isTailOfActivePath(path, getActivePath())) { int newPath = mService.portIdToPath(getActivePortId()); - startRoutingControl(getActivePath(), newPath, true, null); + startRoutingControl(getActivePath(), newPath, null); } } @@ -1161,7 +1160,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { if (!routingForBootup && !isProhibitMode()) { int newPath = mService.portIdToPath(getActivePortId()); setActivePath(newPath); - startRoutingControl(getActivePath(), newPath, routingForBootup, null); + startRoutingControl(getActivePath(), newPath, null); } } else { int activePath = mService.getPhysicalAddress(); diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java index 6c147ed5e6d6..5edd35abf7d1 100644 --- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java +++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java @@ -18,12 +18,11 @@ package com.android.server.hdmi; import android.annotation.Nullable; import android.hardware.hdmi.HdmiControlManager; -import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.IHdmiControlCallback; import android.os.RemoteException; import android.util.Slog; -import com.android.server.hdmi.HdmiControlService.SendMessageCallback; +import com.android.internal.annotations.VisibleForTesting; /** * Feature action for routing control. Exchanges routing-related commands with other devices @@ -43,23 +42,12 @@ final class RoutingControlAction extends HdmiCecFeatureAction { // State in which we wait for <Routing Information> to arrive. If timed out, we use the // latest routing path to set the new active source. - private static final int STATE_WAIT_FOR_ROUTING_INFORMATION = 1; - - // State in which we wait for <Report Power Status> in response to <Give Device Power Status> - // we have sent. If the response tells us the device power is on, we send <Set Stream Path> - // to make it the active source. Otherwise we do not send <Set Stream Path>, and possibly - // just show the blank screen. - private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 2; + @VisibleForTesting + static final int STATE_WAIT_FOR_ROUTING_INFORMATION = 1; // Time out in millseconds used for <Routing Information> private static final int TIMEOUT_ROUTING_INFORMATION_MS = 1000; - // Time out in milliseconds used for <Report Power Status> - private static final int TIMEOUT_REPORT_POWER_STATUS_MS = 1000; - - // true if <Give Power Status> should be sent once the new active routing path is determined. - private final boolean mQueryDevicePowerStatus; - // If set to true, call {@link HdmiControlService#invokeInputChangeListener()} when // the routing control/active source change happens. The listener should be called if // the events are triggered by external events such as manual switch port change or incoming @@ -71,12 +59,10 @@ final class RoutingControlAction extends HdmiCecFeatureAction { // The latest routing path. Updated by each <Routing Information> from CEC switches. private int mCurrentRoutingPath; - RoutingControlAction(HdmiCecLocalDevice localDevice, int path, boolean queryDevicePowerStatus, - IHdmiControlCallback callback) { + RoutingControlAction(HdmiCecLocalDevice localDevice, int path, IHdmiControlCallback callback) { super(localDevice); mCallback = callback; mCurrentRoutingPath = path; - mQueryDevicePowerStatus = queryDevicePowerStatus; // Callback is non-null when routing control action is brought up by binder API. Use // this as an indicator for the input change notification. These API calls will get // the result through this callback, not through notification. Any other events that @@ -109,39 +95,16 @@ final class RoutingControlAction extends HdmiCecFeatureAction { removeActionExcept(RoutingControlAction.class, this); addTimer(mState, TIMEOUT_ROUTING_INFORMATION_MS); return true; - } else if (mState == STATE_WAIT_FOR_REPORT_POWER_STATUS - && opcode == Constants.MESSAGE_REPORT_POWER_STATUS) { - handleReportPowerStatus(cmd.getParams()[0]); - return true; } return false; } - private void handleReportPowerStatus(int devicePowerStatus) { - if (isPowerOnOrTransient(getTvPowerStatus())) { - updateActiveInput(); - if (isPowerOnOrTransient(devicePowerStatus)) { - sendSetStreamPath(); - } - } - finishWithCallback(HdmiControlManager.RESULT_SUCCESS); - } - private void updateActiveInput() { HdmiCecLocalDeviceTv tv = tv(); tv.setPrevPortId(tv.getActivePortId()); tv.updateActiveInput(mCurrentRoutingPath, mNotifyInputChange); } - private int getTvPowerStatus() { - return tv().getPowerStatus(); - } - - private static boolean isPowerOnOrTransient(int status) { - return status == HdmiControlManager.POWER_STATUS_ON - || status == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; - } - private void sendSetStreamPath() { sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(getSourceAddress(), mCurrentRoutingPath)); @@ -160,46 +123,13 @@ final class RoutingControlAction extends HdmiCecFeatureAction { } switch (timeoutState) { case STATE_WAIT_FOR_ROUTING_INFORMATION: - HdmiDeviceInfo device = - localDevice().mService.getHdmiCecNetwork().getDeviceInfoByPath( - mCurrentRoutingPath); - if (device != null && mQueryDevicePowerStatus) { - int deviceLogicalAddress = device.getLogicalAddress(); - queryDevicePowerStatus(deviceLogicalAddress, new SendMessageCallback() { - @Override - public void onSendCompleted(int error) { - handlDevicePowerStatusAckResult( - error == HdmiControlManager.RESULT_SUCCESS); - } - }); - } else { - updateActiveInput(); - finishWithCallback(HdmiControlManager.RESULT_SUCCESS); - } - return; - case STATE_WAIT_FOR_REPORT_POWER_STATUS: - if (isPowerOnOrTransient(getTvPowerStatus())) { - updateActiveInput(); - sendSetStreamPath(); - } + updateActiveInput(); + sendSetStreamPath(); finishWithCallback(HdmiControlManager.RESULT_SUCCESS); return; - } - } - - private void queryDevicePowerStatus(int address, SendMessageCallback callback) { - sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), address), - callback); - } - - private void handlDevicePowerStatusAckResult(boolean acked) { - if (acked) { - mState = STATE_WAIT_FOR_REPORT_POWER_STATUS; - addTimer(mState, TIMEOUT_REPORT_POWER_STATUS_MS); - } else { - updateActiveInput(); - sendSetStreamPath(); - finishWithCallback(HdmiControlManager.RESULT_SUCCESS); + default: + Slog.e("CEC", "Invalid timeoutState (" + timeoutState + ")."); + return; } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 917be29243ad..e72c14e5311b 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -3550,15 +3550,30 @@ public class NotificationManagerService extends SystemService { pkg, uid, channelId, conversationId, true, includeDeleted); } + // Returns 'true' if the given channel has a notification associated + // with an active foreground service. + private void enforceDeletingChannelHasNoFgService(String pkg, int userId, + String channelId) { + if (mAmi.hasForegroundServiceNotification(pkg, userId, channelId)) { + Slog.w(TAG, "Package u" + userId + "/" + pkg + + " may not delete notification channel '" + + channelId + "' with fg service"); + throw new SecurityException("Not allowed to delete channel " + channelId + + " with a foreground service"); + } + } + @Override public void deleteNotificationChannel(String pkg, String channelId) { checkCallerIsSystemOrSameApp(pkg); final int callingUid = Binder.getCallingUid(); + final int callingUser = UserHandle.getUserId(callingUid); if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { throw new IllegalArgumentException("Cannot delete default channel"); } + enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId); cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true, - UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null); + callingUser, REASON_CHANNEL_BANNED, null); mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId); mListeners.notifyNotificationChannelChanged(pkg, UserHandle.getUserHandleForUid(callingUid), @@ -3571,19 +3586,23 @@ public class NotificationManagerService extends SystemService { public void deleteConversationNotificationChannels(String pkg, int uid, String conversationId) { checkCallerIsSystem(); - final int callingUid = Binder.getCallingUid(); List<NotificationChannel> channels = mPreferencesHelper.getNotificationChannelsByConversationId( pkg, uid, conversationId); if (!channels.isEmpty()) { + // Preflight for fg service notifications in these channels: do nothing + // unless they're all eligible + final int appUserId = UserHandle.getUserId(uid); for (NotificationChannel nc : channels) { + final String channelId = nc.getId(); + mAmi.stopForegroundServicesForChannel(pkg, appUserId, channelId); cancelAllNotificationsInt(MY_UID, MY_PID, pkg, nc.getId(), 0, 0, true, - UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null); - mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, nc.getId()); + appUserId, REASON_CHANNEL_BANNED, null); + mPreferencesHelper.deleteNotificationChannel(pkg, uid, channelId); mListeners.notifyNotificationChannelChanged(pkg, - UserHandle.getUserHandleForUid(callingUid), + UserHandle.getUserHandleForUid(uid), mPreferencesHelper.getNotificationChannel( - pkg, callingUid, nc.getId(), true), + pkg, uid, channelId, true), NOTIFICATION_CHANNEL_OR_GROUP_DELETED); } handleSavePolicyFile(); @@ -3614,13 +3633,20 @@ public class NotificationManagerService extends SystemService { NotificationChannelGroup groupToDelete = mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid); if (groupToDelete != null) { + // Preflight for allowability + final int userId = UserHandle.getUserId(callingUid); + List<NotificationChannel> groupChannels = groupToDelete.getChannels(); + for (int i = 0; i < groupChannels.size(); i++) { + enforceDeletingChannelHasNoFgService(pkg, userId, + groupChannels.get(i).getId()); + } List<NotificationChannel> deletedChannels = mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId); for (int i = 0; i < deletedChannels.size(); i++) { final NotificationChannel deletedChannel = deletedChannels.get(i); cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0, true, - UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, + userId, REASON_CHANNEL_BANNED, null); mListeners.notifyNotificationChannelChanged(pkg, UserHandle.getUserHandleForUid(callingUid), diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e6789d4ba8ac..24d550f6da3f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -8942,6 +8942,10 @@ public class PackageManagerService extends IPackageManager.Stub @Override public List<String> getAllPackages() { + // Allow iorapd to call this method. + if (Binder.getCallingUid() != Process.IORAPD_UID) { + enforceSystemOrRootOrShell("getAllPackages is limited to privileged callers"); + } final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); synchronized (mLock) { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 2112247650a5..914c13e30128 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -2907,6 +2907,17 @@ public final class Settings implements Watchable, Snappable { mReadMessages.append("Error reading: " + e.toString()); PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); Slog.wtf(PackageManagerService.TAG, "Error reading package manager settings", e); + } finally { + if (!mVersion.containsKey(StorageManager.UUID_PRIVATE_INTERNAL)) { + Slog.wtf(PackageManagerService.TAG, + "No internal VersionInfo found in settings, using current."); + findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent(); + } + if (!mVersion.containsKey(StorageManager.UUID_PRIMARY_PHYSICAL)) { + Slog.wtf(PackageManagerService.TAG, + "No external VersionInfo found in settings, using current."); + findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent(); + } } // If the build is setup to drop runtime permissions diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java index 5723e1dcceb5..ee30fa2ac928 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java @@ -50,8 +50,6 @@ public final class ClientProfile { */ private final int mProcessId; - private boolean mIsForeground; - /** * All the clients that share the same resource would be under the same group id. * @@ -90,6 +88,12 @@ public final class ClientProfile { private int mUsingCiCamId = INVALID_RESOURCE_ID; /** + * If the priority is overwritten through + * {@link TunerResourceManagerService#setPriority(int, int)}. + */ + private boolean mIsPriorityOverwritten = false; + + /** * Optional arbitrary priority value given by the client. * * <p>This value can override the default priorotiy calculated from @@ -121,17 +125,10 @@ public final class ClientProfile { } /** - * Set the current isForeground status. - */ - public void setForeground(boolean isForeground) { - mIsForeground = isForeground; - } - - /** - * Get the previous recorded isForeground status. + * If the client priority is overwrttien. */ - public boolean isForeground() { - return mIsForeground; + public boolean isPriorityOverwritten() { + return mIsPriorityOverwritten; } public int getGroupId() { @@ -153,6 +150,17 @@ public final class ClientProfile { mPriority = priority; } + /** + * Overwrite the client priority. + */ + public void overwritePriority(int priority) { + if (priority < 0) { + return; + } + mIsPriorityOverwritten = true; + mPriority = priority; + } + public void setNiceValue(int niceValue) { mNiceValue = niceValue; } diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java index 988582da53ea..0c04b075485a 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java @@ -507,9 +507,8 @@ public class TunerResourceManagerService extends SystemService implements IBinde .useCase(profile.useCase) .processId(pid) .build(); - clientProfile.setForeground(checkIsForeground(pid)); clientProfile.setPriority( - getClientPriority(profile.useCase, clientProfile.isForeground())); + getClientPriority(profile.useCase, checkIsForeground(pid))); addClientProfile(clientId[0], clientProfile, listener); } @@ -547,8 +546,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde return false; } - profile.setForeground(checkIsForeground(profile.getProcessId())); - profile.setPriority(priority); + profile.overwritePriority(priority); profile.setNiceValue(niceValue); return true; @@ -694,7 +692,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde } else if (grantingFrontendHandle == TunerResourceManager.INVALID_RESOURCE_HANDLE) { // Record the frontend id with the lowest client priority among all the // in use frontends when no available frontend has been found. - int priority = getOwnerClientPriority(fr.getOwnerClientId()); + int priority = updateAndGetOwnerClientPriority(fr.getOwnerClientId()); if (currentLowestPriority > priority) { inUseLowestPriorityFrHandle = fr.getHandle(); currentLowestPriority = priority; @@ -760,7 +758,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde } else { // Record the lnb id with the lowest client priority among all the // in use lnb when no available lnb has been found. - int priority = getOwnerClientPriority(lnb.getOwnerClientId()); + int priority = updateAndGetOwnerClientPriority(lnb.getOwnerClientId()); if (currentLowestPriority > priority) { inUseLowestPriorityLnbHandle = lnb.getHandle(); currentLowestPriority = priority; @@ -818,7 +816,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde } for (int ownerId : cas.getOwnerClientIds()) { // Record the client id with lowest priority that is using the current Cas system. - int priority = getOwnerClientPriority(ownerId); + int priority = updateAndGetOwnerClientPriority(ownerId); if (currentLowestPriority > priority) { lowestPriorityOwnerId = ownerId; currentLowestPriority = priority; @@ -867,7 +865,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde } for (int ownerId : ciCam.getOwnerClientIds()) { // Record the client id with lowest priority that is using the current Cas system. - int priority = getOwnerClientPriority(ownerId); + int priority = updateAndGetOwnerClientPriority(ownerId); if (currentLowestPriority > priority) { lowestPriorityOwnerId = ownerId; currentLowestPriority = priority; @@ -966,18 +964,17 @@ public class TunerResourceManagerService extends SystemService implements IBinde } @VisibleForTesting - // This mothod is to sync up the request client's foreground/background status and update - // the client priority accordingly whenever new resource request comes in. - protected void clientPriorityUpdateOnRequest(ClientProfile requestProfile) { - int pid = requestProfile.getProcessId(); - boolean currentIsForeground = checkIsForeground(pid); - if (requestProfile.isForeground() == currentIsForeground) { + // This mothod is to sync up the request/holder client's foreground/background status and update + // the client priority accordingly whenever a new resource request comes in. + protected void clientPriorityUpdateOnRequest(ClientProfile profile) { + if (profile.isPriorityOverwritten()) { // To avoid overriding the priority set through updateClientPriority API. return; } - requestProfile.setForeground(currentIsForeground); - requestProfile.setPriority( - getClientPriority(requestProfile.getUseCase(), currentIsForeground)); + int pid = profile.getProcessId(); + boolean currentIsForeground = checkIsForeground(pid); + profile.setPriority( + getClientPriority(profile.getUseCase(), currentIsForeground)); } @VisibleForTesting @@ -1154,13 +1151,15 @@ public class TunerResourceManagerService extends SystemService implements IBinde } /** - * Get the owner client's priority. + * Update and get the owner client's priority. * * @param clientId the owner client id. * @return the priority of the owner client. */ - private int getOwnerClientPriority(int clientId) { - return getClientProfile(clientId).getPriority(); + private int updateAndGetOwnerClientPriority(int clientId) { + ClientProfile profile = getClientProfile(clientId); + clientPriorityUpdateOnRequest(profile); + return profile.getPriority(); } @VisibleForTesting diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java index 4b3a43432fc5..a3ea4c72e36e 100644 --- a/services/core/java/com/android/server/wm/LockTaskController.java +++ b/services/core/java/com/android/server/wm/LockTaskController.java @@ -537,7 +537,7 @@ public class LockTaskController { setStatusBarState(mLockTaskModeState, userId); setKeyguardState(mLockTaskModeState, userId); if (oldLockTaskModeState == LOCK_TASK_MODE_PINNED) { - lockKeyguardIfNeeded(); + lockKeyguardIfNeeded(userId); } if (getDevicePolicyManager() != null) { getDevicePolicyManager().notifyLockTaskModeChanged(false, null, userId); @@ -882,15 +882,15 @@ public class LockTaskController { * Helper method for locking the device immediately. This may be necessary when the device * leaves the pinned mode. */ - private void lockKeyguardIfNeeded() { - if (shouldLockKeyguard()) { + private void lockKeyguardIfNeeded(int userId) { + if (shouldLockKeyguard(userId)) { mWindowManager.lockNow(null); mWindowManager.dismissKeyguard(null /* callback */, null /* message */); getLockPatternUtils().requireCredentialEntry(USER_ALL); } } - private boolean shouldLockKeyguard() { + private boolean shouldLockKeyguard(int userId) { // This functionality should be kept consistent with // com.android.settings.security.ScreenPinningSettings (see b/127605586) try { @@ -900,7 +900,7 @@ public class LockTaskController { } catch (Settings.SettingNotFoundException e) { // Log to SafetyNet for b/127605586 android.util.EventLog.writeEvent(0x534e4554, "127605586", -1, ""); - return getLockPatternUtils().isSecure(USER_CURRENT); + return getLockPatternUtils().isSecure(userId); } } diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index 106db0b15c46..058324c4aa01 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -180,6 +180,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } else if (launchMode == WINDOWING_MODE_FULLSCREEN) { if (DEBUG) appendLog("activity-options-fullscreen=" + outParams.mBounds); } else if (layout != null && canApplyFreeformPolicy) { + mTmpBounds.set(currentParams.mBounds); getLayoutBounds(display, root, layout, mTmpBounds); if (!mTmpBounds.isEmpty()) { launchMode = WINDOWING_MODE_FREEFORM; @@ -492,11 +493,11 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } private void getLayoutBounds(@NonNull DisplayContent display, @NonNull ActivityRecord root, - @NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect outBounds) { + @NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect inOutBounds) { final int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK; final int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; if (!windowLayout.hasSpecifiedSize() && verticalGravity == 0 && horizontalGravity == 0) { - outBounds.setEmpty(); + inOutBounds.setEmpty(); return; } @@ -510,11 +511,17 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { int width; int height; if (!windowLayout.hasSpecifiedSize()) { - outBounds.setEmpty(); - getTaskBounds(root, display, windowLayout, WINDOWING_MODE_FREEFORM, - /* hasInitialBounds */ false, outBounds); - width = outBounds.width(); - height = outBounds.height(); + if (!inOutBounds.isEmpty()) { + // If the bounds is resolved already and WindowLayout doesn't have any opinion on + // its size, use the already resolved size and apply the gravity to it. + width = inOutBounds.width(); + height = inOutBounds.height(); + } else { + getTaskBounds(root, display, windowLayout, WINDOWING_MODE_FREEFORM, + /* hasInitialBounds */ false, inOutBounds); + width = inOutBounds.width(); + height = inOutBounds.height(); + } } else { width = defaultWidth; if (windowLayout.width > 0 && windowLayout.width < defaultWidth) { @@ -555,11 +562,11 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { fractionOfVerticalOffset = 0.5f; } - outBounds.set(0, 0, width, height); - outBounds.offset(displayStableBounds.left, displayStableBounds.top); + inOutBounds.set(0, 0, width, height); + inOutBounds.offset(displayStableBounds.left, displayStableBounds.top); final int xOffset = (int) (fractionOfHorizontalOffset * (defaultWidth - width)); final int yOffset = (int) (fractionOfVerticalOffset * (defaultHeight - height)); - outBounds.offset(xOffset, yOffset); + inOutBounds.offset(xOffset, yOffset); } /** diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 1cf4ce163640..b0422a5b8e31 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -8693,6 +8693,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return null; } final ComponentName supervisorComponent = ComponentName.unflattenFromString(supervisor); + if (supervisorComponent == null) { + return null; + } if (supervisorComponent.equals(doComponent) || supervisorComponent.equals( poComponent)) { return supervisorComponent; diff --git a/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerPerUserService.java b/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerPerUserService.java index 0cb729d924b4..87b2c84a30f7 100644 --- a/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerPerUserService.java +++ b/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerPerUserService.java @@ -16,6 +16,7 @@ package com.android.server.musicrecognition; +import static android.Manifest.permission.RECORD_AUDIO; import static android.media.musicrecognition.MusicRecognitionManager.RECOGNITION_FAILED_AUDIO_UNAVAILABLE; import static android.media.musicrecognition.MusicRecognitionManager.RECOGNITION_FAILED_SERVICE_KILLED; import static android.media.musicrecognition.MusicRecognitionManager.RECOGNITION_FAILED_SERVICE_UNAVAILABLE; @@ -25,6 +26,7 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppGlobals; +import android.app.AppOpsManager; import android.content.ComponentName; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; @@ -45,6 +47,7 @@ import com.android.server.infra.AbstractPerUserSystemService; import java.io.IOException; import java.io.OutputStream; +import java.util.Objects; /** * Handles per-user requests received by @@ -64,11 +67,20 @@ public final class MusicRecognitionManagerPerUserService extends @Nullable @GuardedBy("mLock") private RemoteMusicRecognitionService mRemoteService; + private final AppOpsManager mAppOpsManager; + + private String mAttributionTag; + private String mAttributionMessage; + private ServiceInfo mServiceInfo; MusicRecognitionManagerPerUserService( @NonNull MusicRecognitionManagerService primary, @NonNull Object lock, int userId) { super(primary, lock, userId); + mAppOpsManager = getContext().getSystemService(AppOpsManager.class); + mAttributionMessage = String.format("MusicRecognitionManager.invokedByUid.%s", userId); + mAttributionTag = null; + mServiceInfo = null; } @NonNull @@ -114,6 +126,13 @@ public final class MusicRecognitionManagerPerUserService extends new MusicRecognitionServiceCallback(clientCallback), mMaster.isBindInstantServiceAllowed(), mMaster.verbose); + try { + mServiceInfo = + getContext().getPackageManager().getServiceInfo( + mRemoteService.getComponentName(), 0); + } catch (PackageManager.NameNotFoundException e) { + Slog.e(TAG, "Service was not found.", e); + } } return mRemoteService; @@ -127,12 +146,8 @@ public final class MusicRecognitionManagerPerUserService extends public void beginRecognitionLocked( @NonNull RecognitionRequest recognitionRequest, @NonNull IBinder callback) { - int maxAudioLengthSeconds = Math.min(recognitionRequest.getMaxAudioLengthSeconds(), - MAX_STREAMING_SECONDS); IMusicRecognitionManagerCallback clientCallback = IMusicRecognitionManagerCallback.Stub.asInterface(callback); - AudioRecord audioRecord = createAudioRecord(recognitionRequest, maxAudioLengthSeconds); - mRemoteService = ensureRemoteServiceLocked(clientCallback); if (mRemoteService == null) { try { @@ -158,52 +173,92 @@ public final class MusicRecognitionManagerPerUserService extends ParcelFileDescriptor clientRead = clientPipe.first; mMaster.mExecutorService.execute(() -> { - try (OutputStream fos = - new ParcelFileDescriptor.AutoCloseOutputStream(audioSink)) { - int halfSecondBufferSize = - audioRecord.getBufferSizeInFrames() / maxAudioLengthSeconds; - byte[] byteBuffer = new byte[halfSecondBufferSize]; - int bytesRead = 0; - int totalBytesRead = 0; - int ignoreBytes = - recognitionRequest.getIgnoreBeginningFrames() * BYTES_PER_SAMPLE; - audioRecord.startRecording(); - while (bytesRead >= 0 && totalBytesRead - < audioRecord.getBufferSizeInFrames() * BYTES_PER_SAMPLE - && mRemoteService != null) { - bytesRead = audioRecord.read(byteBuffer, 0, byteBuffer.length); - if (bytesRead > 0) { - totalBytesRead += bytesRead; - // If we are ignoring the first x bytes, update that counter. - if (ignoreBytes > 0) { - ignoreBytes -= bytesRead; - // If we've dipped negative, we've skipped through all ignored bytes - // and then some. Write out the bytes we shouldn't have skipped. - if (ignoreBytes < 0) { - fos.write(byteBuffer, bytesRead + ignoreBytes, -ignoreBytes); - } - } else { - fos.write(byteBuffer); - } - } - } - Slog.i(TAG, String.format("Streamed %s bytes from audio record", totalBytesRead)); - } catch (IOException e) { - Slog.e(TAG, "Audio streaming stopped.", e); - } finally { - audioRecord.release(); - try { - clientCallback.onAudioStreamClosed(); - } catch (RemoteException ignored) { - // Ignored. - } - } + streamAudio(recognitionRequest, clientCallback, audioSink); }); // Send the pipe down to the lookup service while we write to it asynchronously. mRemoteService.writeAudioToPipe(clientRead, recognitionRequest.getAudioFormat()); } /** + * Streams audio based on given request to the given audioSink. Notifies callback of errors. + * + * @param recognitionRequest the recognition request specifying audio parameters. + * @param clientCallback the callback to notify on errors. + * @param audioSink the sink to which to stream audio to. + */ + private void streamAudio(@NonNull RecognitionRequest recognitionRequest, + IMusicRecognitionManagerCallback clientCallback, ParcelFileDescriptor audioSink) { + try { + startRecordAudioOp(); + } catch (SecurityException e) { + // A security exception can occur if the MusicRecognitionService (receiving the audio) + // does not (or does no longer) hold the necessary permissions to record audio. + Slog.e(TAG, "RECORD_AUDIO op not permitted on behalf of " + + mServiceInfo.getComponentName(), e); + try { + clientCallback.onRecognitionFailed( + RECOGNITION_FAILED_AUDIO_UNAVAILABLE); + } catch (RemoteException ignored) { + // Ignored. + } + return; + } + + int maxAudioLengthSeconds = Math.min(recognitionRequest.getMaxAudioLengthSeconds(), + MAX_STREAMING_SECONDS); + AudioRecord audioRecord = createAudioRecord(recognitionRequest, maxAudioLengthSeconds); + try (OutputStream fos = + new ParcelFileDescriptor.AutoCloseOutputStream(audioSink)) { + streamAudio(recognitionRequest, maxAudioLengthSeconds, audioRecord, fos); + } catch (IOException e) { + Slog.e(TAG, "Audio streaming stopped.", e); + } finally { + audioRecord.release(); + finishRecordAudioOp(); + try { + clientCallback.onAudioStreamClosed(); + } catch (RemoteException ignored) { + // Ignored. + } + } + } + + /** Performs the actual streaming from audioRecord into outputStream. **/ + private void streamAudio(@NonNull RecognitionRequest recognitionRequest, + int maxAudioLengthSeconds, AudioRecord audioRecord, OutputStream outputStream) + throws IOException { + int halfSecondBufferSize = + audioRecord.getBufferSizeInFrames() / maxAudioLengthSeconds; + byte[] byteBuffer = new byte[halfSecondBufferSize]; + int bytesRead = 0; + int totalBytesRead = 0; + int ignoreBytes = + recognitionRequest.getIgnoreBeginningFrames() * BYTES_PER_SAMPLE; + audioRecord.startRecording(); + while (bytesRead >= 0 && totalBytesRead + < audioRecord.getBufferSizeInFrames() * BYTES_PER_SAMPLE + && mRemoteService != null) { + bytesRead = audioRecord.read(byteBuffer, 0, byteBuffer.length); + if (bytesRead > 0) { + totalBytesRead += bytesRead; + // If we are ignoring the first x bytes, update that counter. + if (ignoreBytes > 0) { + ignoreBytes -= bytesRead; + // If we've dipped negative, we've skipped through all ignored bytes + // and then some. Write out the bytes we shouldn't have skipped. + if (ignoreBytes < 0) { + outputStream.write(byteBuffer, bytesRead + ignoreBytes, -ignoreBytes); + } + } else { + outputStream.write(byteBuffer); + } + } + } + Slog.i(TAG, + String.format("Streamed %s bytes from audio record", totalBytesRead)); + } + + /** * Callback invoked by {@link android.service.musicrecognition.MusicRecognitionService} to pass * back the music search result. */ @@ -264,6 +319,29 @@ public final class MusicRecognitionManagerPerUserService extends } } + /** + * Tracks that the RECORD_AUDIO operation started (attributes it to the service receiving the + * audio). + */ + private void startRecordAudioOp() { + mAppOpsManager.startProxyOp( + Objects.requireNonNull(AppOpsManager.permissionToOp(RECORD_AUDIO)), + mServiceInfo.applicationInfo.uid, + mServiceInfo.packageName, + mAttributionTag, + mAttributionMessage); + } + + + /** Tracks that the RECORD_AUDIO operation finished. */ + private void finishRecordAudioOp() { + mAppOpsManager.finishProxyOp( + Objects.requireNonNull(AppOpsManager.permissionToOp(RECORD_AUDIO)), + mServiceInfo.applicationInfo.uid, + mServiceInfo.packageName, + mAttributionTag); + } + /** Establishes an audio stream from the DSP audio source. */ private static AudioRecord createAudioRecord( @NonNull RecognitionRequest recognitionRequest, diff --git a/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerService.java b/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerService.java index 38f43138aee0..e145d3301292 100644 --- a/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerService.java +++ b/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerService.java @@ -45,7 +45,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** - * Service which allows a DSP audio event to be securely streamed to a designated {@link + * Service which allows audio to be securely streamed to a designated {@link * MusicRecognitionService}. */ public class MusicRecognitionManagerService extends diff --git a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java index a19b3872949e..363c26b63bae 100644 --- a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java @@ -21,7 +21,6 @@ import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -53,9 +52,7 @@ import com.android.server.twilight.TwilightManager; import com.android.server.twilight.TwilightState; import org.junit.After; -import org.junit.AfterClass; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; @@ -76,25 +73,29 @@ public class ColorDisplayServiceTest { private int mUserId; private MockTwilightManager mTwilightManager; + private DisplayTransformManager mDisplayTransformManager; private ColorDisplayService mCds; private ColorDisplayService.BinderService mBinderService; private Resources mResourcesSpy; - @BeforeClass - public static void setDtm() { - final DisplayTransformManager dtm = Mockito.mock(DisplayTransformManager.class); - LocalServices.addService(DisplayTransformManager.class, dtm); - } + private static final int[] MINIMAL_COLOR_MODES = new int[] { + ColorDisplayManager.COLOR_MODE_NATURAL, + ColorDisplayManager.COLOR_MODE_BOOSTED, + }; @Before public void setUp() { mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); doReturn(mContext).when(mContext).getApplicationContext(); - mResourcesSpy = Mockito.spy(mContext.getResources()); - when(mContext.getResources()).thenReturn(mResourcesSpy); + final Resources res = Mockito.spy(mContext.getResources()); + doReturn(MINIMAL_COLOR_MODES).when(res).getIntArray(R.array.config_availableColorModes); + doReturn(true).when(res).getBoolean(R.bool.config_nightDisplayAvailable); + doReturn(true).when(res).getBoolean(R.bool.config_displayWhiteBalanceAvailable); + when(mContext.getResources()).thenReturn(res); + mResourcesSpy = res; mUserId = ActivityManager.getCurrentUser(); @@ -108,6 +109,10 @@ public class ColorDisplayServiceTest { mTwilightManager = new MockTwilightManager(); LocalServices.addService(TwilightManager.class, mTwilightManager); + mDisplayTransformManager = Mockito.mock(DisplayTransformManager.class); + doReturn(true).when(mDisplayTransformManager).needsLinearColorMatrix(); + LocalServices.addService(DisplayTransformManager.class, mDisplayTransformManager); + mCds = new ColorDisplayService(mContext); mBinderService = mCds.new BinderService(); LocalServices.addService(ColorDisplayService.ColorDisplayServiceInternal.class, @@ -116,12 +121,18 @@ public class ColorDisplayServiceTest { @After public void tearDown() { - LocalServices.removeServiceForTest(TwilightManager.class); - + /* + * Wait for internal {@link Handler} to finish processing pending messages, so that test + * code can safelyremove {@link DisplayTransformManager} mock from {@link LocalServices}. + */ + mCds.mHandler.runWithScissors(() -> { /* nop */ }, /* timeout */ 1000); mCds = null; + LocalServices.removeServiceForTest(TwilightManager.class); mTwilightManager = null; + LocalServices.removeServiceForTest(DisplayTransformManager.class); + mUserId = UserHandle.USER_NULL; mContext = null; @@ -130,11 +141,6 @@ public class ColorDisplayServiceTest { LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class); } - @AfterClass - public static void removeDtm() { - LocalServices.removeServiceForTest(DisplayTransformManager.class); - } - @Test public void customSchedule_whenStartedAfterNight_ifOffAfterNight_turnsOff() { setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */); @@ -1064,24 +1070,18 @@ public class ColorDisplayServiceTest { @Test public void compositionColorSpaces_noResources() { - final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class); - reset(dtm); - when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes)) .thenReturn(new int[] {}); when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces)) .thenReturn(new int[] {}); setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL); startService(); - verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), - eq(Display.COLOR_MODE_INVALID)); + verify(mDisplayTransformManager).setColorMode( + eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), eq(Display.COLOR_MODE_INVALID)); } @Test public void compositionColorSpaces_invalidResources() { - final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class); - reset(dtm); - when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes)) .thenReturn(new int[] { ColorDisplayManager.COLOR_MODE_NATURAL, @@ -1094,15 +1094,12 @@ public class ColorDisplayServiceTest { }); setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL); startService(); - verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), - eq(Display.COLOR_MODE_INVALID)); + verify(mDisplayTransformManager).setColorMode( + eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), eq(Display.COLOR_MODE_INVALID)); } @Test public void compositionColorSpaces_validResources_validColorMode() { - final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class); - reset(dtm); - when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes)) .thenReturn(new int[] { ColorDisplayManager.COLOR_MODE_NATURAL @@ -1113,15 +1110,12 @@ public class ColorDisplayServiceTest { }); setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL); startService(); - verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), - eq(Display.COLOR_MODE_SRGB)); + verify(mDisplayTransformManager).setColorMode( + eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), eq(Display.COLOR_MODE_SRGB)); } @Test public void compositionColorSpaces_validResources_invalidColorMode() { - final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class); - reset(dtm); - when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes)) .thenReturn(new int[] { ColorDisplayManager.COLOR_MODE_NATURAL @@ -1132,8 +1126,8 @@ public class ColorDisplayServiceTest { }); setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED); startService(); - verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_BOOSTED), any(), - eq(Display.COLOR_MODE_INVALID)); + verify(mDisplayTransformManager).setColorMode( + eq(ColorDisplayManager.COLOR_MODE_BOOSTED), any(), eq(Display.COLOR_MODE_INVALID)); } /** diff --git a/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java new file mode 100644 index 000000000000..0ed6d7bec010 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.hdmi; + +import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM; +import static com.android.server.hdmi.Constants.ADDR_BROADCAST; +import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1; +import static com.android.server.hdmi.Constants.ADDR_TUNER_1; +import static com.android.server.hdmi.Constants.ADDR_TV; +import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED; +import static com.android.server.hdmi.Constants.MESSAGE_ACTIVE_SOURCE; +import static com.android.server.hdmi.Constants.MESSAGE_ROUTING_INFORMATION; +import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC; +import static com.android.server.hdmi.RoutingControlAction.STATE_WAIT_FOR_ROUTING_INFORMATION; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.hardware.hdmi.HdmiDeviceInfo; +import android.hardware.hdmi.HdmiPortInfo; +import android.hardware.hdmi.IHdmiControlCallback; +import android.os.Handler; +import android.os.IPowerManager; +import android.os.IThermalService; +import android.os.Looper; +import android.os.PowerManager; +import android.os.test.TestLooper; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; + +import com.android.server.hdmi.HdmiCecFeatureAction.ActionTimer; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +@SmallTest +@RunWith(JUnit4.class) +public class RoutingControlActionTest { + /* + * Example connection diagram used in tests. Double-lined paths indicate the currently active + * routes. + * + * + * +-----------+ + * | TV | + * | 0.0.0.0 | + * +---+-----+-+ + * | | + * <----------+ 1) AVR -> Switch + * +----------+ | | +-----------+ + * | AVR +---------+ +--+ Switch | + * | 1.0.0.0 | | 2.0.0.0 | + * +--+---++--+ +--++-----+-+ <-------+ 2) Recorder -> Blu-ray + * | || || | + * | || || +--------+ + * +-----------+ | || +----------+ +----++----+ | + * | XBox +--+ ++--+ Tuner | | Blueray | +-----+----+ + * | 1.1.0.0 | | 1.2.0.0 | | 2.1.0.0 | | Recorder | + * +-----------+ +----++----+ +----------+ | 2.2.0.0 | + * || +----------+ + * || + * +----++----+ + * | Player | + * | 1.2.1.0 | + * +----------+ + * + */ + + private static final int PHYSICAL_ADDRESS_TV = 0x0000; + private static final int PHYSICAL_ADDRESS_AVR = 0x1000; + private static final int PHYSICAL_ADDRESS_SWITCH = 0x2000; + private static final int PHYSICAL_ADDRESS_TUNER = 0x1200; + private static final int PHYSICAL_ADDRESS_PLAYER = 0x1210; + private static final int PHYSICAL_ADDRESS_BLUERAY = 0x2100; + private static final int PHYSICAL_ADDRESS_RECORDER = 0x2200; + private static final int PORT_1 = 1; + private static final int PORT_2 = 2; + private static final int VENDOR_ID_AVR = 0x11233; + + private static final byte[] TUNER_PARAM = + new byte[] {(PHYSICAL_ADDRESS_TUNER >> 8) & 0xFF, PHYSICAL_ADDRESS_TUNER & 0xFF}; + private static final byte[] PLAYER_PARAM = + new byte[] {(PHYSICAL_ADDRESS_PLAYER >> 8) & 0xFF, PHYSICAL_ADDRESS_PLAYER & 0xFF}; + + private static final HdmiDeviceInfo DEVICE_INFO_AVR = + new HdmiDeviceInfo(ADDR_AUDIO_SYSTEM, PHYSICAL_ADDRESS_AVR, PORT_1, + HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM, VENDOR_ID_AVR, "Audio"); + private static final HdmiDeviceInfo DEVICE_INFO_PLAYER = + new HdmiDeviceInfo(ADDR_PLAYBACK_1, PHYSICAL_ADDRESS_PLAYER, PORT_1, + HdmiDeviceInfo.DEVICE_PLAYBACK, VENDOR_ID_AVR, "Player"); + private static final HdmiCecMessage ROUTING_INFORMATION_TUNER = new HdmiCecMessage( + ADDR_UNREGISTERED, ADDR_BROADCAST, MESSAGE_ROUTING_INFORMATION, TUNER_PARAM); + private static final HdmiCecMessage ROUTING_INFORMATION_PLAYER = new HdmiCecMessage( + ADDR_UNREGISTERED, ADDR_BROADCAST, MESSAGE_ROUTING_INFORMATION, PLAYER_PARAM); + private static final HdmiCecMessage ACTIVE_SOURCE_TUNER = new HdmiCecMessage( + ADDR_TUNER_1, ADDR_BROADCAST, MESSAGE_ACTIVE_SOURCE, TUNER_PARAM); + private static final HdmiCecMessage ACTIVE_SOURCE_PLAYER = new HdmiCecMessage( + ADDR_PLAYBACK_1, ADDR_BROADCAST, MESSAGE_ACTIVE_SOURCE, PLAYER_PARAM); + + private HdmiControlService mHdmiControlService; + private HdmiCecController mHdmiCecController; + private HdmiCecLocalDeviceTv mHdmiCecLocalDeviceTv; + private FakeNativeWrapper mNativeWrapper; + private Looper mMyLooper; + private TestLooper mTestLooper = new TestLooper(); + private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>(); + + @Mock + private IPowerManager mIPowerManagerMock; + @Mock + private IThermalService mIThermalServiceMock; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + Context context = InstrumentationRegistry.getTargetContext(); + mMyLooper = mTestLooper.getLooper(); + PowerManager powerManager = new PowerManager(context, mIPowerManagerMock, + mIThermalServiceMock, new Handler(mMyLooper)); + + HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context); + + mHdmiControlService = + new HdmiControlService(InstrumentationRegistry.getTargetContext()) { + @Override + boolean isControlEnabled() { + return true; + } + + @Override + void wakeUp() { + } + + @Override + protected void writeStringSystemProperty(String key, String value) { + // do nothing + } + + @Override + boolean isPowerStandbyOrTransient() { + return false; + } + + @Override + protected PowerManager getPowerManager() { + return powerManager; + } + + @Override + protected HdmiCecConfig getHdmiCecConfig() { + return hdmiCecConfig; + } + }; + + mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService); + mHdmiCecLocalDeviceTv.init(); + mHdmiControlService.setIoLooper(mMyLooper); + mNativeWrapper = new FakeNativeWrapper(); + mHdmiCecController = HdmiCecController.createWithNativeWrapper( + mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); + mHdmiControlService.setCecController(mHdmiCecController); + mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService)); + mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService)); + mLocalDevices.add(mHdmiCecLocalDeviceTv); + HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1]; + hdmiPortInfos[0] = + new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, PHYSICAL_ADDRESS_AVR, + true, false, false); + mNativeWrapper.setPortInfo(hdmiPortInfos); + mHdmiControlService.initService(); + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mNativeWrapper.setPhysicalAddress(0x0000); + mTestLooper.dispatchAll(); + mNativeWrapper.clearResultMessages(); + mHdmiControlService.getHdmiCecNetwork().addCecDevice(DEVICE_INFO_AVR); + } + + private static class TestActionTimer implements ActionTimer { + private int mState; + + @Override + public void sendTimerMessage(int state, long delayMillis) { + mState = state; + } + + @Override + public void clearTimerMessage() { + } + + private int getState() { + return mState; + } + } + + private static class TestInputSelectCallback extends IHdmiControlCallback.Stub { + private final List<Integer> mCallbackResult = new ArrayList<Integer>(); + + @Override + public void onComplete(int result) { + mCallbackResult.add(result); + } + + private int getResult() { + assert (mCallbackResult.size() == 1); + return mCallbackResult.get(0); + } + } + + private static RoutingControlAction createRoutingControlAction(HdmiCecLocalDeviceTv localDevice, + TestInputSelectCallback callback) { + return new RoutingControlAction(localDevice, PHYSICAL_ADDRESS_AVR, callback); + } + + // Routing control succeeds against the device connected directly to the port. Action + // won't get any <Routing Information> in this case. It times out on <Routing Information>, + // regards the directly connected one as the new routing path to switch to. + @Test + public void testRoutingControl_succeedForDirectlyConnectedDevice() { + TestInputSelectCallback callback = new TestInputSelectCallback(); + TestActionTimer actionTimer = new TestActionTimer(); + mHdmiControlService.getHdmiCecNetwork().addCecDevice(DEVICE_INFO_AVR); + + RoutingControlAction action = createRoutingControlAction(mHdmiCecLocalDeviceTv, callback); + action.setActionTimer(actionTimer); + action.start(); + assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_ROUTING_INFORMATION); + + action.handleTimerEvent(actionTimer.getState()); + mTestLooper.dispatchAll(); + HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath( + ADDR_TV, PHYSICAL_ADDRESS_AVR); + assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath); + } + + // Succeeds by receiving a couple of <Routing Information> commands, followed by + // <Set Stream Path> going out in the end. + @Test + public void testRoutingControl_succeedForDeviceBehindSwitch() { + TestInputSelectCallback callback = new TestInputSelectCallback(); + TestActionTimer actionTimer = new TestActionTimer(); + mHdmiControlService.getHdmiCecNetwork().addCecDevice(DEVICE_INFO_PLAYER); + RoutingControlAction action = createRoutingControlAction(mHdmiCecLocalDeviceTv, callback); + action.setActionTimer(actionTimer); + action.start(); + + assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_ROUTING_INFORMATION); + + action.processCommand(ROUTING_INFORMATION_TUNER); + action.processCommand(ROUTING_INFORMATION_PLAYER); + + action.handleTimerEvent(actionTimer.getState()); + mTestLooper.dispatchAll(); + HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath( + ADDR_TV, PHYSICAL_ADDRESS_PLAYER); + assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath); + } +} diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java index aadab6ea4fd9..2f36c7fb9044 100644 --- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java @@ -365,13 +365,13 @@ public class TunerResourceManagerServiceTest { mTunerResourceManagerService.registerClientProfileInternal( profiles[0], listener, clientId0); assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId0[0]) - .setPriority(clientPriorities[0]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId0[0], clientPriorities[0], 0/*niceValue*/); mTunerResourceManagerService.registerClientProfileInternal( profiles[1], new TestResourcesReclaimListener(), clientId1); assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId1[0]) - .setPriority(clientPriorities[1]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId1[0], clientPriorities[1], 0/*niceValue*/); // Init frontend resources. TunerFrontendInfo[] infos = new TunerFrontendInfo[2]; @@ -415,13 +415,13 @@ public class TunerResourceManagerServiceTest { mTunerResourceManagerService.registerClientProfileInternal( profiles[0], listener, clientId0); assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId0[0]) - .setPriority(clientPriorities[0]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId0[0], clientPriorities[0], 0/*niceValue*/); mTunerResourceManagerService.registerClientProfileInternal( profiles[1], new TestResourcesReclaimListener(), clientId1); assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId1[0]) - .setPriority(clientPriorities[1]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId1[0], clientPriorities[1], 0/*niceValue*/); // Init frontend resources. TunerFrontendInfo[] infos = new TunerFrontendInfo[2]; @@ -511,13 +511,13 @@ public class TunerResourceManagerServiceTest { mTunerResourceManagerService.registerClientProfileInternal( profiles[0], listener, clientId0); assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId0[0]) - .setPriority(clientPriorities[0]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId0[0], clientPriorities[0], 0/*niceValue*/); mTunerResourceManagerService.registerClientProfileInternal( profiles[1], new TestResourcesReclaimListener(), clientId1); assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId1[0]) - .setPriority(clientPriorities[1]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId1[0], clientPriorities[1], 0/*niceValue*/); // Init cas resources. mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/); @@ -567,13 +567,13 @@ public class TunerResourceManagerServiceTest { mTunerResourceManagerService.registerClientProfileInternal( profiles[0], listener, clientId0); assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId0[0]) - .setPriority(clientPriorities[0]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId0[0], clientPriorities[0], 0/*niceValue*/); mTunerResourceManagerService.registerClientProfileInternal( profiles[1], new TestResourcesReclaimListener(), clientId1); assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId1[0]) - .setPriority(clientPriorities[1]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId1[0], clientPriorities[1], 0/*niceValue*/); // Init cicam/cas resources. mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/); @@ -697,13 +697,13 @@ public class TunerResourceManagerServiceTest { mTunerResourceManagerService.registerClientProfileInternal( profiles[0], listener, clientId0); assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId0[0]) - .setPriority(clientPriorities[0]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId0[0], clientPriorities[0], 0/*niceValue*/); mTunerResourceManagerService.registerClientProfileInternal( profiles[1], new TestResourcesReclaimListener(), clientId1); assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId1[0]) - .setPriority(clientPriorities[1]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId1[0], clientPriorities[1], 0/*niceValue*/); // Init lnb resources. int[] lnbHandles = {1}; diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java index f935bfcd9068..14dacc10f7eb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java @@ -453,7 +453,7 @@ public class LockTaskControllerTest { Settings.Secure.clearProviderForTest(); // AND a password is set - when(mLockPatternUtils.isSecure(anyInt())) + when(mLockPatternUtils.isSecure(TEST_USER_ID)) .thenReturn(true); // AND there is a task record diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java index 49847992125e..ea8619fe7fa8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -521,6 +521,7 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { WINDOWING_MODE_FULLSCREEN); } + @Test public void testKeepsPictureInPictureLaunchModeInOptions() { final TestDisplayContent freeformDisplay = createNewDisplayContent( @@ -588,11 +589,14 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { } @Test - public void testNonEmptyLayoutInfersFreeformWithEmptySize() { + public void testLayoutWithGravityAndEmptySizeInfersFreeformAndRespectsCurrentSize() { final TestDisplayContent freeformDisplay = createNewDisplayContent( WINDOWING_MODE_FREEFORM); + final Rect expectedLaunchBounds = new Rect(0, 0, 200, 100); + mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea(); + mCurrent.mBounds.set(expectedLaunchBounds); final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder() .setGravity(Gravity.LEFT).build(); @@ -600,6 +604,9 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setLayout(layout).calculate()); + assertEquals(expectedLaunchBounds.width(), mResult.mBounds.width()); + assertEquals(expectedLaunchBounds.height(), mResult.mBounds.height()); + assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode, WINDOWING_MODE_FREEFORM); } |