summaryrefslogtreecommitdiff
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java5
-rw-r--r--services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java20
-rw-r--r--services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java34
-rw-r--r--services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java7
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java4
-rw-r--r--services/core/java/com/android/server/BluetoothService.java7
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java14
-rw-r--r--services/core/java/com/android/server/EventLogTags.logtags6
-rw-r--r--services/core/java/com/android/server/MountServiceIdler.java25
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java18
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java9
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java95
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java19
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java15
-rw-r--r--services/core/java/com/android/server/am/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java94
-rw-r--r--services/core/java/com/android/server/audio/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java4
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java50
-rw-r--r--services/core/java/com/android/server/connectivity/DataConnectionStats.java3
-rw-r--r--services/core/java/com/android/server/display/ColorFade.java9
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java189
-rw-r--r--services/core/java/com/android/server/display/color/ColorDisplayService.java9
-rw-r--r--services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java27
-rw-r--r--services/core/java/com/android/server/display/color/TintController.java26
-rw-r--r--services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java14
-rw-r--r--services/core/java/com/android/server/infra/AbstractMasterSystemService.java156
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java4
-rw-r--r--services/core/java/com/android/server/notification/BubbleExtractor.java3
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java380
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java245
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java55
-rw-r--r--services/core/java/com/android/server/notification/RankingConfig.java2
-rw-r--r--services/core/java/com/android/server/notification/ZenLog.java1
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java5
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java52
-rw-r--r--services/core/java/com/android/server/pm/ProtectedPackages.java3
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java1
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java206
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java10
-rw-r--r--services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java86
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java26
-rw-r--r--services/core/java/com/android/server/power/ThermalManagerService.java13
-rw-r--r--services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java7
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java12
-rw-r--r--services/core/java/com/android/server/webkit/WebViewUpdater.java13
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java26
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java30
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java25
-rw-r--r--services/core/java/com/android/server/wm/BlackFrame.java12
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java17
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java3
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowSettings.java28
-rw-r--r--services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java4
-rw-r--r--services/core/java/com/android/server/wm/Letterbox.java2
-rw-r--r--services/core/java/com/android/server/wm/RootActivityContainer.java23
-rw-r--r--services/core/java/com/android/server/wm/RunningTasks.java5
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java8
-rw-r--r--services/core/java/com/android/server/wm/TaskChangeNotificationController.java21
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java2
-rw-r--r--services/java/com/android/server/SystemServer.java35
-rw-r--r--services/net/java/android/net/ConnectivityModuleConnector.java36
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java36
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java10
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java229
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java90
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java30
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DimmerTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java37
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java48
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java8
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java33
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java9
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java2
84 files changed, 1969 insertions, 885 deletions
diff --git a/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java
index 672518cc17ed..b9b2654b93cc 100644
--- a/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java
+++ b/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java
@@ -24,10 +24,7 @@ import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
-import android.view.IWindowManager;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -191,7 +188,7 @@ public class GlobalActionPerformer {
ScreenshotHelper screenshotHelper = (mScreenshotHelperSupplier != null)
? mScreenshotHelperSupplier.get() : new ScreenshotHelper(mContext);
screenshotHelper.takeScreenshot(android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN,
- true, true, new Handler(Looper.getMainLooper()));
+ true, true, new Handler(Looper.getMainLooper()), null);
return true;
}
}
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
index d7e68f896c6c..5844f9873001 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
@@ -23,6 +23,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppPredictionSessionId;
import android.app.prediction.AppTargetEvent;
@@ -61,7 +62,8 @@ public class AppPredictionManagerService extends
public AppPredictionManagerService(Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context,
- com.android.internal.R.string.config_defaultAppPredictionService), null);
+ com.android.internal.R.string.config_defaultAppPredictionService), null,
+ PACKAGE_UPDATE_POLICY_NO_REFRESH | PACKAGE_RESTART_POLICY_NO_REFRESH);
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
}
@@ -80,6 +82,22 @@ public class AppPredictionManagerService extends
getContext().enforceCallingPermission(MANAGE_APP_PREDICTIONS, TAG);
}
+ @Override // from AbstractMasterSystemService
+ protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
+ final AppPredictionPerUserService service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ service.onPackageUpdatedLocked();
+ }
+ }
+
+ @Override // from AbstractMasterSystemService
+ protected void onServicePackageRestartedLocked(@UserIdInt int userId) {
+ final AppPredictionPerUserService service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ service.onPackageRestartedLocked();
+ }
+ }
+
@Override
protected int getMaximumTemporaryServiceDurationMs() {
return MAX_TEMP_SERVICE_DURATION_MS;
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 03c4542a50d4..4f49fb7578a1 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -251,6 +251,40 @@ public class AppPredictionPerUserService extends
// Do nothing, eventually the system will bind to the remote service again...
}
+ void onPackageUpdatedLocked() {
+ if (isDebug()) {
+ Slog.v(TAG, "onPackageUpdatedLocked()");
+ }
+ destroyAndRebindRemoteService();
+ }
+
+ void onPackageRestartedLocked() {
+ if (isDebug()) {
+ Slog.v(TAG, "onPackageRestartedLocked()");
+ }
+ destroyAndRebindRemoteService();
+ }
+
+ private void destroyAndRebindRemoteService() {
+ if (mRemoteService == null) {
+ return;
+ }
+
+ if (isDebug()) {
+ Slog.d(TAG, "Destroying the old remote service.");
+ }
+ mRemoteService.destroy();
+ mRemoteService = null;
+
+ mRemoteService = getRemoteServiceLocked();
+ if (mRemoteService != null) {
+ if (isDebug()) {
+ Slog.d(TAG, "Rebinding to the new remote service.");
+ }
+ mRemoteService.reconnect();
+ }
+ }
+
/**
* Called after the remote service connected, it's used to restore state from a 'zombie'
* service (i.e., after it died).
diff --git a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
index c82e7a012fff..04e0e7f7102f 100644
--- a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
+++ b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
@@ -135,6 +135,13 @@ public class RemoteAppPredictionService extends
}
/**
+ * Schedules a request to bind to the remote service.
+ */
+ public void reconnect() {
+ super.scheduleBind();
+ }
+
+ /**
* Failure callback
*/
public interface RemoteAppPredictionServiceCallbacks
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index d260985190f7..87991beefcee 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2407,7 +2407,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// Update the view states first...
mCurrentViewId = viewState.id;
- viewState.setCurrentValue(value);
+ if (value != null) {
+ viewState.setCurrentValue(value);
+ }
if (mCompatMode && (viewState.getState() & ViewState.STATE_URL_BAR) != 0) {
if (sDebug) Slog.d(TAG, "Ignoring VIEW_ENTERED on URL BAR (id=" + id + ")");
diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java
index 5c5b477352b1..6a6ddc84be49 100644
--- a/services/core/java/com/android/server/BluetoothService.java
+++ b/services/core/java/com/android/server/BluetoothService.java
@@ -54,8 +54,11 @@ class BluetoothService extends SystemService {
@Override
public void onSwitchUser(int userHandle) {
- initialize();
- mBluetoothManagerService.handleOnSwitchUser(userHandle);
+ if (!mInitialized) {
+ initialize();
+ } else {
+ mBluetoothManagerService.handleOnSwitchUser(userHandle);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 52a4218238e7..2ab46e65e77f 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -2737,7 +2737,9 @@ public class DeviceIdleController extends SystemService
resetIdleManagementLocked();
// Wait a small amount of time in case something (eg: background service from
// recently closed app) needs to finish running.
- scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false);
+ // Use a non-wakeup alarm for going into quick doze in case an AlarmClock alarm
+ // is scheduled soon. The non-wakeup alarm will be delayed by at most 2 minutes.
+ scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false, false);
EventLogTags.writeDeviceIdle(mState, "no activity");
} else if (mState == STATE_ACTIVE) {
mState = STATE_INACTIVE;
@@ -3362,6 +3364,10 @@ public class DeviceIdleController extends SystemService
}
void scheduleAlarmLocked(long delay, boolean idleUntil) {
+ scheduleAlarmLocked(delay, idleUntil, true);
+ }
+
+ private void scheduleAlarmLocked(long delay, boolean idleUntil, boolean useWakeupAlarm) {
if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")");
if (mUseMotionSensor && mMotionSensor == null
@@ -3377,12 +3383,14 @@ public class DeviceIdleController extends SystemService
// can continue until the user interacts with the device.
return;
}
+ final int alarmType = useWakeupAlarm
+ ? AlarmManager.ELAPSED_REALTIME_WAKEUP : AlarmManager.ELAPSED_REALTIME;
mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
if (idleUntil) {
- mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mAlarmManager.setIdleUntil(alarmType,
mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
} else {
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mAlarmManager.set(alarmType,
mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
}
}
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 4d39f9ab8d78..bec08f45188f 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -39,6 +39,12 @@ option java_package com.android.server
27391 user_activity_timeout_override (override|2|3)
27392 battery_saver_setting (threshold|1)
+
+# ---------------------------
+# ThermalManagerService.java
+# ---------------------------
+2737 thermal_changed (name|3),(type|1|5),(temperature|5),(sensor_status|1|5),(previous_system_status|1|5)
+
#
# Leave IDs through 2740 for more power logs (2730 used by battery_discharge above)
#
diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java
index 1891ba9b1742..6bc1a570b7c0 100644
--- a/services/core/java/com/android/server/MountServiceIdler.java
+++ b/services/core/java/com/android/server/MountServiceIdler.java
@@ -27,6 +27,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.os.RemoteException;
import android.util.Slog;
+import java.util.concurrent.TimeUnit;
public class MountServiceIdler extends JobService {
private static final String TAG = "MountServiceIdler";
@@ -48,7 +49,7 @@ public class MountServiceIdler extends JobService {
mStarted = false;
}
}
- // ... and try again tomorrow
+ // ... and try again right away or tomorrow
scheduleIdlePass(MountServiceIdler.this);
}
};
@@ -98,24 +99,32 @@ public class MountServiceIdler extends JobService {
public static void scheduleIdlePass(Context context) {
JobScheduler tm = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
- Calendar calendar = tomorrowMidnight();
- final long timeToMidnight = calendar.getTimeInMillis() - System.currentTimeMillis();
+ final long today3AM = offsetFromTodayMidnight(0, 3).getTimeInMillis();
+ final long today4AM = offsetFromTodayMidnight(0, 4).getTimeInMillis();
+ final long tomorrow3AM = offsetFromTodayMidnight(1, 3).getTimeInMillis();
+
+ long nextScheduleTime;
+ if (System.currentTimeMillis() > today3AM && System.currentTimeMillis() < today4AM) {
+ nextScheduleTime = TimeUnit.SECONDS.toMillis(10);
+ } else {
+ nextScheduleTime = tomorrow3AM - System.currentTimeMillis(); // 3AM tomorrow
+ }
JobInfo.Builder builder = new JobInfo.Builder(MOUNT_JOB_ID, sIdleService);
builder.setRequiresDeviceIdle(true);
- builder.setRequiresCharging(true);
- builder.setMinimumLatency(timeToMidnight);
+ builder.setRequiresBatteryNotLow(true);
+ builder.setMinimumLatency(nextScheduleTime);
tm.schedule(builder.build());
}
- private static Calendar tomorrowMidnight() {
+ private static Calendar offsetFromTodayMidnight(int nDays, int nHours) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
- calendar.set(Calendar.HOUR_OF_DAY, 3);
+ calendar.set(Calendar.HOUR_OF_DAY, nHours);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
- calendar.add(Calendar.DAY_OF_MONTH, 1);
+ calendar.add(Calendar.DAY_OF_MONTH, nDays);
return calendar;
}
}
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 30a356325ada..6b038979a98d 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -48,7 +48,6 @@ import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.SystemProperties;
import android.os.UserHandle;
-import android.os.UserManager;
import android.provider.Settings.Secure;
import android.service.dreams.Sandman;
import android.service.vr.IVrManager;
@@ -218,6 +217,15 @@ final class UiModeManagerService extends SystemService {
}
};
+ private final ContentObserver mDarkThemeObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ final int mode = Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.UI_NIGHT_MODE, mNightMode, 0);
+ SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode));
+ }
+ };
+
@Override
public void onSwitchUser(int userHandle) {
super.onSwitchUser(userHandle);
@@ -293,6 +301,9 @@ final class UiModeManagerService extends SystemService {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
context.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler);
+
+ context.getContentResolver().registerContentObserver(Secure.getUriFor(Secure.UI_NIGHT_MODE),
+ false, mDarkThemeObserver, 0);
}
// Records whether setup wizard has happened or not and adds an observer for this user if not.
@@ -417,11 +428,6 @@ final class UiModeManagerService extends SystemService {
if (!mCarModeEnabled) {
Secure.putIntForUser(getContext().getContentResolver(),
Secure.UI_NIGHT_MODE, mode, user);
-
- if (UserManager.get(getContext()).isPrimaryUser()) {
- SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME,
- Integer.toString(mode));
- }
}
mNightMode = mode;
diff --git a/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java b/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java
index 9e5f7229d382..9bf0bd357f37 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java
@@ -17,6 +17,7 @@
package com.android.server.accounts;
import android.annotation.NonNull;
+import android.app.ActivityManager;
import android.os.ShellCommand;
import android.os.UserHandle;
@@ -83,7 +84,7 @@ final class AccountManagerServiceShellCommand extends ShellCommand {
return null;
}
}
- return UserHandle.USER_SYSTEM;
+ return ActivityManager.getCurrentUser();
}
@Override
@@ -92,9 +93,11 @@ final class AccountManagerServiceShellCommand extends ShellCommand {
pw.println("Account manager service commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println(" set-bind-instant-service-allowed [--user <USER_ID>] true|false ");
+ pw.println(" set-bind-instant-service-allowed "
+ + "[--user <USER_ID> (current user if not specified)] true|false ");
pw.println(" Set whether binding to services provided by instant apps is allowed.");
- pw.println(" get-bind-instant-service-allowed [--user <USER_ID>]");
+ pw.println(" get-bind-instant-service-allowed "
+ + "[--user <USER_ID> (current user if not specified)]");
pw.println(" Get whether binding to services provided by instant apps is allowed.");
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5af1480af94b..5ffdf02ef11e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5276,6 +5276,9 @@ public class ActivityManagerService extends IActivityManager.Stub
// Inform checkpointing systems of success
try {
+ // This line is needed to CTS test for the correct exception handling
+ // See b/138952436#comment36 for context
+ Slog.i(TAG, "About to commit checkpoint");
IStorageManager storageManager = PackageHelper.getStorageManager();
storageManager.commitChanges();
} catch (Exception e) {
@@ -9052,7 +9055,16 @@ public class ActivityManagerService extends IActivityManager.Stub
Integer.toString(currentUserId), currentUserId);
mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START,
Integer.toString(currentUserId), currentUserId);
- mSystemServiceManager.startUser(currentUserId);
+
+ // On Automotive, at this point the system user has already been started and unlocked,
+ // and some of the tasks we do here have already been done. So skip those in that case.
+ // TODO(b/132262830): this workdound shouldn't be necessary once we move the
+ // headless-user start logic to UserManager-land
+ final boolean bootingSystemUser = currentUserId == UserHandle.USER_SYSTEM;
+
+ if (bootingSystemUser) {
+ mSystemServiceManager.startUser(currentUserId);
+ }
synchronized (this) {
// Only start up encryption-aware persistent apps; once user is
@@ -9076,43 +9088,53 @@ public class ActivityManagerService extends IActivityManager.Stub
throw e.rethrowAsRuntimeException();
}
}
- mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
+
+ if (bootingSystemUser) {
+ mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
+ }
mAtmInternal.showSystemReadyErrorDialogsIfNeeded();
- final int callingUid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
- long ident = Binder.clearCallingIdentity();
- try {
- Intent intent = new Intent(Intent.ACTION_USER_STARTED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
- | Intent.FLAG_RECEIVER_FOREGROUND);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
- broadcastIntentLocked(null, null, intent,
- null, null, 0, null, null, null, OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
- currentUserId);
- intent = new Intent(Intent.ACTION_USER_STARTING);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
- broadcastIntentLocked(null, null, intent,
- null, new IIntentReceiver.Stub() {
- @Override
- public void performReceive(Intent intent, int resultCode, String data,
- Bundle extras, boolean ordered, boolean sticky, int sendingUser)
- throws RemoteException {
- }
- }, 0, null, null,
- new String[] {INTERACT_ACROSS_USERS}, OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
- UserHandle.USER_ALL);
- } catch (Throwable t) {
- Slog.wtf(TAG, "Failed sending first user broadcasts", t);
- } finally {
- Binder.restoreCallingIdentity(ident);
+ if (bootingSystemUser) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ long ident = Binder.clearCallingIdentity();
+ try {
+ Intent intent = new Intent(Intent.ACTION_USER_STARTED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
+ broadcastIntentLocked(null, null, intent,
+ null, null, 0, null, null, null, OP_NONE,
+ null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+ currentUserId);
+ intent = new Intent(Intent.ACTION_USER_STARTING);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
+ broadcastIntentLocked(null, null, intent,
+ null, new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode, String data,
+ Bundle extras, boolean ordered, boolean sticky, int sendingUser)
+ throws RemoteException {
+ }
+ }, 0, null, null,
+ new String[] {INTERACT_ACROSS_USERS}, OP_NONE,
+ null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+ UserHandle.USER_ALL);
+ } catch (Throwable t) {
+ Slog.wtf(TAG, "Failed sending first user broadcasts", t);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ } else {
+ Slog.i(TAG, "Not sending multi-user broadcasts for non-system user "
+ + currentUserId);
}
mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
- mUserController.sendUserSwitchBroadcasts(-1, currentUserId);
+ if (bootingSystemUser) {
+ mUserController.sendUserSwitchBroadcasts(-1, currentUserId);
+ }
BinderInternal.nSetBinderProxyCountWatermarks(BINDER_PROXY_HIGH_WATERMARK,
BINDER_PROXY_LOW_WATERMARK);
@@ -15004,7 +15026,12 @@ public class ActivityManagerService extends IActivityManager.Stub
final int uid = getUidFromIntent(intent);
if (uid >= 0) {
mBatteryStatsService.removeUid(uid);
- mAppOpsService.uidRemoved(uid);
+ if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ mAppOpsService.resetAllModes(UserHandle.getUserId(uid),
+ intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME));
+ } else {
+ mAppOpsService.uidRemoved(uid);
+ }
}
break;
case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 567404697395..8c60d0c759dc 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -722,10 +722,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
}
- public void notePhoneDataConnectionState(int dataType, boolean hasData) {
+ public void notePhoneDataConnectionState(int dataType, boolean hasData, int serviceType) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.notePhoneDataConnectionStateLocked(dataType, hasData);
+ mStats.notePhoneDataConnectionStateLocked(dataType, hasData, serviceType);
}
}
@@ -756,7 +756,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
public void noteStartAudio(int uid) {
- enforceSelfOrCallingPermission(uid);
+ enforceCallingPermission();
synchronized (mStats) {
mStats.noteAudioOnLocked(uid);
StatsLog.write_non_chained(StatsLog.AUDIO_STATE_CHANGED, uid, null,
@@ -765,7 +765,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
public void noteStopAudio(int uid) {
- enforceSelfOrCallingPermission(uid);
+ enforceCallingPermission();
synchronized (mStats) {
mStats.noteAudioOffLocked(uid);
StatsLog.write_non_chained(StatsLog.AUDIO_STATE_CHANGED, uid, null,
@@ -774,7 +774,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
public void noteStartVideo(int uid) {
- enforceSelfOrCallingPermission(uid);
+ enforceCallingPermission();
synchronized (mStats) {
mStats.noteVideoOnLocked(uid);
StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, uid, null,
@@ -783,7 +783,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
public void noteStopVideo(int uid) {
- enforceSelfOrCallingPermission(uid);
+ enforceCallingPermission();
synchronized (mStats) {
mStats.noteVideoOffLocked(uid);
StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, uid,
@@ -1184,13 +1184,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub
Binder.getCallingPid(), Binder.getCallingUid(), null);
}
- private void enforceSelfOrCallingPermission(int uid) {
- if (Binder.getCallingUid() == uid) {
- return;
- }
- enforceCallingPermission();
- }
-
final class WakeupReasonThread extends Thread {
private static final int MAX_REASON_SIZE = 512;
private CharsetDecoder mDecoder;
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 4692fd4eeb2e..a2670d8dd424 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2098,10 +2098,10 @@ public final class ProcessList {
}
}
}
- if (lrui <= mLruProcessActivityStart) {
+ if (lrui < mLruProcessActivityStart) {
mLruProcessActivityStart--;
}
- if (lrui <= mLruProcessServiceStart) {
+ if (lrui < mLruProcessServiceStart) {
mLruProcessServiceStart--;
}
mLruProcesses.remove(lrui);
@@ -2633,7 +2633,7 @@ public final class ProcessList {
if (!moved) {
// Goes to the end of the group.
mLruProcesses.remove(i);
- mLruProcesses.add(endIndex - 1, subProc);
+ mLruProcesses.add(endIndex, subProc);
if (DEBUG_LRU) Slog.d(TAG_LRU,
"Moving " + subProc
+ " from position " + i + " to end of group @ "
@@ -2878,15 +2878,6 @@ public final class ProcessList {
pos--;
}
mLruProcesses.add(pos, app);
- if (pos == mLruProcessActivityStart) {
- mLruProcessActivityStart++;
- }
- if (pos == mLruProcessServiceStart) {
- // Unless {@code #hasService} is implemented, currently the starting position
- // for activity and service are the same, so the incoming position may equal to
- // the starting position of service.
- mLruProcessServiceStart++;
- }
// If this process is part of a group, need to pull up any other processes
// in that group to be with it.
int endIndex = pos - 1;
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index e9151d499706..21d4925722d0 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -14,9 +14,6 @@
},
{
"exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-filter": "android.app.cts.SystemFeaturesTest#testLocationFeatures"
}
]
},
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index a35d2ee38641..314e04c8da32 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -18,9 +18,11 @@ package com.android.server.appop;
import static android.app.AppOpsManager.MAX_PRIORITY_UID_STATE;
import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE;
+import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_FLAGS_ALL;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
import static android.app.AppOpsManager.UID_STATE_CACHED;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
@@ -173,6 +175,12 @@ public class AppOpsService extends IAppOpsService.Stub {
UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
};
+ private static final int[] OPS_RESTRICTED_ON_SUSPEND = {
+ OP_PLAY_AUDIO,
+ OP_RECORD_AUDIO,
+ OP_CAMERA,
+ };
+
Context mContext;
final AtomicFile mFile;
final Handler mHandler;
@@ -510,6 +518,10 @@ public class AppOpsService extends IAppOpsService.Stub {
private void updateProxyState(long key, int proxyUid,
@Nullable String proxyPackageName) {
+ if (proxyUid == Process.INVALID_UID) {
+ return;
+ }
+
if (mProxyUids == null) {
mProxyUids = new LongSparseLongArray();
}
@@ -789,20 +801,22 @@ public class AppOpsService extends IAppOpsService.Stub {
final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
final String[] changedPkgs = intent.getStringArrayExtra(
Intent.EXTRA_CHANGED_PACKAGE_LIST);
- ArraySet<ModeCallback> callbacks;
- synchronized (AppOpsService.this) {
- callbacks = mOpModeWatchers.get(OP_PLAY_AUDIO);
- if (callbacks == null) {
- return;
+ for (int code : OPS_RESTRICTED_ON_SUSPEND) {
+ ArraySet<ModeCallback> callbacks;
+ synchronized (AppOpsService.this) {
+ callbacks = mOpModeWatchers.get(code);
+ if (callbacks == null) {
+ continue;
+ }
+ callbacks = new ArraySet<>(callbacks);
+ }
+ for (int i = 0; i < changedUids.length; i++) {
+ final int changedUid = changedUids[i];
+ final String changedPkg = changedPkgs[i];
+ // We trust packagemanager to insert matching uid and packageNames in the
+ // extras
+ notifyOpChanged(callbacks, code, changedUid, changedPkg);
}
- callbacks = new ArraySet<>(callbacks);
- }
- for (int i = 0; i < changedUids.length; i++) {
- final int changedUid = changedUids[i];
- final String changedPkg = changedPkgs[i];
- // We trust packagemanager to insert matching uid and packageNames in the
- // extras
- notifyOpChanged(callbacks, OP_PLAY_AUDIO, changedUid, changedPkg);
}
}
}, packageSuspendFilter);
@@ -1805,6 +1819,9 @@ public class AppOpsService extends IAppOpsService.Stub {
*/
private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
boolean raw, boolean verify) {
+ if (isOpRestrictedDueToSuspend(code, packageName, uid)) {
+ return AppOpsManager.MODE_IGNORED;
+ }
synchronized (this) {
if (verify) {
checkPackage(uid, packageName);
@@ -2659,6 +2676,14 @@ public class AppOpsService extends IAppOpsService.Stub {
return op;
}
+ private boolean isOpRestrictedDueToSuspend(int code, String packageName, int uid) {
+ if (!ArrayUtils.contains(OPS_RESTRICTED_ON_SUSPEND, code)) {
+ return false;
+ }
+ final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+ return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid));
+ }
+
private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
int userHandle = UserHandle.getUserId(uid);
final int restrictionSetCount = mOpUserRestrictions.size();
@@ -2984,17 +3009,40 @@ public class AppOpsService extends IAppOpsService.Stub {
out.startTag(null, "app-ops");
out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
- final int uidStateCount = mUidStates.size();
- for (int i = 0; i < uidStateCount; i++) {
- UidState uidState = mUidStates.valueAt(i);
- if (uidState.opModes != null && uidState.opModes.size() > 0) {
+ SparseArray<SparseIntArray> uidStatesClone;
+ synchronized (this) {
+ uidStatesClone = new SparseArray<>(mUidStates.size());
+
+ final int uidStateCount = mUidStates.size();
+ for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
+ UidState uidState = mUidStates.valueAt(uidStateNum);
+ int uid = mUidStates.keyAt(uidStateNum);
+
+ SparseIntArray opModes = uidState.opModes;
+ if (opModes != null && opModes.size() > 0) {
+ uidStatesClone.put(uid, new SparseIntArray(opModes.size()));
+
+ final int opCount = opModes.size();
+ for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
+ uidStatesClone.get(uid).put(
+ opModes.keyAt(opCountNum),
+ opModes.valueAt(opCountNum));
+ }
+ }
+ }
+ }
+
+ final int uidStateCount = uidStatesClone.size();
+ for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
+ SparseIntArray opModes = uidStatesClone.valueAt(uidStateNum);
+ if (opModes != null && opModes.size() > 0) {
out.startTag(null, "uid");
- out.attribute(null, "n", Integer.toString(uidState.uid));
- SparseIntArray uidOpModes = uidState.opModes;
- final int opCount = uidOpModes.size();
- for (int j = 0; j < opCount; j++) {
- final int op = uidOpModes.keyAt(j);
- final int mode = uidOpModes.valueAt(j);
+ out.attribute(null, "n",
+ Integer.toString(uidStatesClone.keyAt(uidStateNum)));
+ final int opCount = opModes.size();
+ for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
+ final int op = opModes.keyAt(opCountNum);
+ final int mode = opModes.valueAt(opCountNum);
out.startTag(null, "op");
out.attribute(null, "n", Integer.toString(op));
out.attribute(null, "m", Integer.toString(mode));
diff --git a/services/core/java/com/android/server/audio/TEST_MAPPING b/services/core/java/com/android/server/audio/TEST_MAPPING
index bf09eac1b422..0d34c5372914 100644
--- a/services/core/java/com/android/server/audio/TEST_MAPPING
+++ b/services/core/java/com/android/server/audio/TEST_MAPPING
@@ -8,9 +8,6 @@
},
{
"include-filter": "android.media.cts.AudioFocusTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index ee49f5885e4a..387d7a85f4a8 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -53,6 +53,7 @@ import android.os.SELinux;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.util.Slog;
import com.android.internal.R;
@@ -926,7 +927,8 @@ public class FaceService extends BiometricServiceBase {
final Face face = new Face("", 0 /* identifier */, deviceId);
FaceService.super.handleRemoved(face, 0 /* remaining */);
}
-
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_RE_ENROLL, 0, UserHandle.USER_CURRENT);
});
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index acb0207ff11f..85ca627e3b02 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -35,6 +35,8 @@ import android.hardware.broadcastradio.V2_0.Result;
import android.hardware.broadcastradio.V2_0.VendorKeyValue;
import android.hardware.radio.RadioManager;
import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.util.MutableInt;
import android.util.Slog;
@@ -44,6 +46,7 @@ import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@@ -55,6 +58,7 @@ class RadioModule {
@NonNull public final RadioManager.ModuleProperties mProperties;
private final Object mLock = new Object();
+ @NonNull private final Handler mHandler;
@GuardedBy("mLock")
private ITunerSession mHalTunerSession;
@@ -70,38 +74,46 @@ class RadioModule {
private final ITunerCallback mHalTunerCallback = new ITunerCallback.Stub() {
@Override
public void onTuneFailed(int result, ProgramSelector programSelector) {
- fanoutAidlCallback(cb -> cb.onTuneFailed(result, Convert.programSelectorFromHal(
- programSelector)));
+ lockAndFireLater(() -> {
+ android.hardware.radio.ProgramSelector csel =
+ Convert.programSelectorFromHal(programSelector);
+ fanoutAidlCallbackLocked(cb -> cb.onTuneFailed(result, csel));
+ });
}
@Override
public void onCurrentProgramInfoChanged(ProgramInfo halProgramInfo) {
- RadioManager.ProgramInfo programInfo = Convert.programInfoFromHal(halProgramInfo);
- synchronized (mLock) {
- mProgramInfo = programInfo;
- fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(programInfo));
- }
+ lockAndFireLater(() -> {
+ mProgramInfo = Convert.programInfoFromHal(halProgramInfo);
+ fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(mProgramInfo));
+ });
}
@Override
public void onProgramListUpdated(ProgramListChunk programListChunk) {
// TODO: Cache per-AIDL client filters, send union of filters to HAL, use filters to fan
// back out to clients.
- fanoutAidlCallback(cb -> cb.onProgramListUpdated(Convert.programListChunkFromHal(
- programListChunk)));
+ lockAndFireLater(() -> {
+ android.hardware.radio.ProgramList.Chunk chunk =
+ Convert.programListChunkFromHal(programListChunk);
+ fanoutAidlCallbackLocked(cb -> cb.onProgramListUpdated(chunk));
+ });
}
@Override
public void onAntennaStateChange(boolean connected) {
- synchronized (mLock) {
+ lockAndFireLater(() -> {
mAntennaConnected = connected;
fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected));
- }
+ });
}
@Override
public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) {
- fanoutAidlCallback(cb -> cb.onParametersUpdated(Convert.vendorInfoFromHal(parameters)));
+ lockAndFireLater(() -> {
+ Map<String, String> cparam = Convert.vendorInfoFromHal(parameters);
+ fanoutAidlCallbackLocked(cb -> cb.onParametersUpdated(cparam));
+ });
}
};
@@ -113,6 +125,7 @@ class RadioModule {
@NonNull RadioManager.ModuleProperties properties) throws RemoteException {
mProperties = Objects.requireNonNull(properties);
mService = Objects.requireNonNull(service);
+ mHandler = new Handler(Looper.getMainLooper());
}
public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName) {
@@ -201,15 +214,22 @@ class RadioModule {
}
}
+ // add to mHandler queue, but ensure the runnable holds mLock when it gets executed
+ private void lockAndFireLater(Runnable r) {
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ r.run();
+ }
+ });
+ }
+
interface AidlCallbackRunnable {
void run(android.hardware.radio.ITunerCallback callback) throws RemoteException;
}
// Invokes runnable with each TunerSession currently open.
void fanoutAidlCallback(AidlCallbackRunnable runnable) {
- synchronized (mLock) {
- fanoutAidlCallbackLocked(runnable);
- }
+ lockAndFireLater(() -> fanoutAidlCallbackLocked(runnable));
}
private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) {
diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
index e6a4428ef219..27f11ffa60ce 100644
--- a/services/core/java/com/android/server/connectivity/DataConnectionStats.java
+++ b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
@@ -97,7 +97,8 @@ public class DataConnectionStats extends BroadcastReceiver {
if (DEBUG) Log.d(TAG, String.format("Noting data connection for network type %s: %svisible",
networkType, visible ? "" : "not "));
try {
- mBatteryStats.notePhoneDataConnectionState(networkType, visible);
+ mBatteryStats.notePhoneDataConnectionState(networkType, visible,
+ mServiceState.getState());
} catch (RemoteException e) {
Log.w(TAG, "Error noting data connection state", e);
}
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index f61306405daa..c46fc20b3cc8 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -649,13 +649,8 @@ final class ColorFade {
if (mSurfaceControl != null) {
mSurfaceLayout.dispose();
mSurfaceLayout = null;
- SurfaceControl.openTransaction();
- try {
- mSurfaceControl.remove();
- mSurface.release();
- } finally {
- SurfaceControl.closeTransaction();
- }
+ new Transaction().remove(mSurfaceControl).apply();
+ mSurface.release();
mSurfaceControl = null;
mSurfaceVisible = false;
mSurfaceAlpha = 0f;
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 97fd02f53513..1fc0db3ff7cb 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -69,6 +69,7 @@ public class DisplayModeDirector {
private static final int MSG_ALLOWED_MODES_CHANGED = 1;
private static final int MSG_BRIGHTNESS_THRESHOLDS_CHANGED = 2;
private static final int MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED = 3;
+ private static final int MSG_REFRESH_RATE_IN_ZONE_CHANGED = 4;
// Special ID used to indicate that given vote is to be applied globally, rather than to a
// specific display.
@@ -440,23 +441,48 @@ public class DisplayModeDirector {
mSettingsObserver.onDeviceConfigDefaultPeakRefreshRateChanged(
defaultPeakRefreshRate);
break;
+
+ case MSG_REFRESH_RATE_IN_ZONE_CHANGED:
+ int refreshRateInZone = msg.arg1;
+ mBrightnessObserver.onDeviceConfigRefreshRateInZoneChanged(
+ refreshRateInZone);
+ break;
}
}
}
private static final class Vote {
- // We split the app request into two priorities in case we can satisfy one desire without
- // the other.
- public static final int PRIORITY_APP_REQUEST_REFRESH_RATE = 0;
- public static final int PRIORITY_APP_REQUEST_SIZE = 1;
- public static final int PRIORITY_USER_SETTING_REFRESH_RATE = 2;
- public static final int PRIORITY_LOW_BRIGHTNESS = 3;
- public static final int PRIORITY_LOW_POWER_MODE = 4;
+ // LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null.
+ // If the higher voters result is a range, it will fix the rate to a single choice.
+ // It's used to avoid rate switch in certain conditions.
+ public static final int PRIORITY_LOW_BRIGHTNESS = 0;
+
+ // SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate.
+ // It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY]
+ public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 1;
+
+ // We split the app request into different priorities in case we can satisfy one desire
+ // without the other.
+
+ // Application can specify preferred refresh rate with below attrs.
+ // @see android.view.WindowManager.LayoutParams#preferredRefreshRate
+ // @see android.view.WindowManager.LayoutParams#preferredDisplayModeId
+ // System also forces some apps like blacklisted app to run at a lower refresh rate.
+ // @see android.R.array#config_highRefreshRateBlacklist
+ public static final int PRIORITY_APP_REQUEST_REFRESH_RATE = 2;
+ public static final int PRIORITY_APP_REQUEST_SIZE = 3;
+
+ // SETTING_PEAK_REFRESH_RATE has a high priority and will restrict the bounds of the rest
+ // of low priority voters. It votes [0, max(PEAK, MIN)]
+ public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 4;
+
+ // LOW_POWER_MODE force display to [0, 60HZ] if Settings.Global.LOW_POWER_MODE is on.
+ public static final int PRIORITY_LOW_POWER_MODE = 5;
// Whenever a new priority is added, remember to update MIN_PRIORITY and/or MAX_PRIORITY as
// appropriate, as well as priorityToString.
- public static final int MIN_PRIORITY = PRIORITY_APP_REQUEST_REFRESH_RATE;
+ public static final int MIN_PRIORITY = PRIORITY_LOW_BRIGHTNESS;
public static final int MAX_PRIORITY = PRIORITY_LOW_POWER_MODE;
/**
@@ -500,12 +526,16 @@ public class DisplayModeDirector {
public static String priorityToString(int priority) {
switch (priority) {
+ case PRIORITY_LOW_BRIGHTNESS:
+ return "PRIORITY_LOW_BRIGHTNESS";
+ case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
+ return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE";
case PRIORITY_APP_REQUEST_REFRESH_RATE:
return "PRIORITY_APP_REQUEST_REFRESH_RATE";
case PRIORITY_APP_REQUEST_SIZE:
return "PRIORITY_APP_REQUEST_SIZE";
- case PRIORITY_USER_SETTING_REFRESH_RATE:
- return "PRIORITY_USER_SETTING_REFRESH_RATE";
+ case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE:
+ return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE";
case PRIORITY_LOW_POWER_MODE:
return "PRIORITY_LOW_POWER_MODE";
default:
@@ -608,12 +638,11 @@ public class DisplayModeDirector {
float peakRefreshRate = Settings.System.getFloat(mContext.getContentResolver(),
Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate);
- if (peakRefreshRate < minRefreshRate) {
- peakRefreshRate = minRefreshRate;
- }
+ updateVoteLocked(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE,
+ Vote.forRefreshRates(0f, Math.max(minRefreshRate, peakRefreshRate)));
+ updateVoteLocked(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE,
+ Vote.forRefreshRates(minRefreshRate, Float.POSITIVE_INFINITY));
- Vote vote = Vote.forRefreshRates(minRefreshRate, peakRefreshRate);
- updateVoteLocked(Vote.PRIORITY_USER_SETTING_REFRESH_RATE, vote);
mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, peakRefreshRate);
}
@@ -655,6 +684,7 @@ public class DisplayModeDirector {
refreshRateVote = null;
sizeVote = null;
}
+
updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, refreshRateVote);
updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_SIZE, sizeVote);
return;
@@ -736,6 +766,7 @@ public class DisplayModeDirector {
@Override
public void onDisplayChanged(int displayId) {
updateDisplayModes(displayId);
+ mBrightnessObserver.onDisplayChanged(displayId);
}
private void updateDisplayModes(int displayId) {
@@ -790,7 +821,6 @@ public class DisplayModeDirector {
private AmbientFilter mAmbientFilter;
private final Context mContext;
- private final ScreenStateReceiver mScreenStateReceiver;
// Enable light sensor only when mShouldObserveAmbientChange is true, screen is on, peak
// refresh rate changeable and low power mode off. After initialization, these states will
@@ -799,10 +829,11 @@ public class DisplayModeDirector {
private boolean mRefreshRateChangeable = false;
private boolean mLowPowerModeEnabled = false;
+ private int mRefreshRateInZone;
+
BrightnessObserver(Context context, Handler handler) {
super(handler);
mContext = context;
- mScreenStateReceiver = new ScreenStateReceiver(mContext);
mDisplayBrightnessThresholds = context.getResources().getIntArray(
R.array.config_brightnessThresholdsOfPeakRefreshRate);
mAmbientBrightnessThresholds = context.getResources().getIntArray(
@@ -816,6 +847,7 @@ public class DisplayModeDirector {
public void observe(SensorManager sensorManager) {
mSensorManager = sensorManager;
+
// DeviceConfig is accessible after system ready.
int[] brightnessThresholds = mDeviceConfigDisplaySettings.getBrightnessThresholds();
int[] ambientThresholds = mDeviceConfigDisplaySettings.getAmbientThresholds();
@@ -825,6 +857,8 @@ public class DisplayModeDirector {
mDisplayBrightnessThresholds = brightnessThresholds;
mAmbientBrightnessThresholds = ambientThresholds;
}
+
+ mRefreshRateInZone = mDeviceConfigDisplaySettings.getRefreshRateInZone();
restartObserver();
mDeviceConfigDisplaySettings.startListening();
}
@@ -864,8 +898,16 @@ public class DisplayModeDirector {
restartObserver();
}
+ public void onDeviceConfigRefreshRateInZoneChanged(int refreshRate) {
+ if (refreshRate != mRefreshRateInZone) {
+ mRefreshRateInZone = refreshRate;
+ restartObserver();
+ }
+ }
+
public void dumpLocked(PrintWriter pw) {
pw.println(" BrightnessObserver");
+ pw.println(" mRefreshRateInZone: " + mRefreshRateInZone);
for (int d: mDisplayBrightnessThresholds) {
pw.println(" mDisplayBrightnessThreshold: " + d);
@@ -876,12 +918,16 @@ public class DisplayModeDirector {
}
}
+ public void onDisplayChanged(int displayId) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ onScreenOn(isDefaultDisplayOn());
+ }
+ }
+
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
synchronized (mLock) {
- if (mRefreshRateChangeable) {
- onBrightnessChangedLocked();
- }
+ onBrightnessChangedLocked();
}
}
@@ -927,16 +973,11 @@ public class DisplayModeDirector {
mAmbientFilter = DisplayWhiteBalanceFactory.createBrightnessFilter(res);
mLightSensor = lightSensor;
- // Intent.ACTION_SCREEN_ON is not sticky. Check current screen status.
- if (mContext.getSystemService(PowerManager.class).isInteractive()) {
- onScreenOn(true);
- }
- mScreenStateReceiver.register();
+ onScreenOn(isDefaultDisplayOn());
}
} else {
mAmbientFilter = null;
mLightSensor = null;
- mScreenStateReceiver.unregister();
}
if (mRefreshRateChangeable) {
@@ -952,6 +993,10 @@ public class DisplayModeDirector {
* to value changes.
*/
private boolean checkShouldObserve(int[] a) {
+ if (mRefreshRateInZone <= 0) {
+ return false;
+ }
+
for (int d: a) {
if (d >= 0) {
return true;
@@ -961,44 +1006,47 @@ public class DisplayModeDirector {
return false;
}
- private void onBrightnessChangedLocked() {
- int brightness = Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS, -1);
-
- Vote vote = null;
+ private boolean isInsideZone(int brightness, float lux) {
for (int i = 0; i < mDisplayBrightnessThresholds.length; i++) {
int disp = mDisplayBrightnessThresholds[i];
int ambi = mAmbientBrightnessThresholds[i];
if (disp >= 0 && ambi >= 0) {
if (brightness <= disp && mAmbientLux <= ambi) {
- vote = Vote.forRefreshRates(0f, 60f);
+ return true;
}
} else if (disp >= 0) {
if (brightness <= disp) {
- vote = Vote.forRefreshRates(0f, 60f);
+ return true;
}
} else if (ambi >= 0) {
if (mAmbientLux <= ambi) {
- vote = Vote.forRefreshRates(0f, 60f);
+ return true;
}
}
+ }
- if (vote != null) {
- break;
- }
+ return false;
+ }
+
+ private void onBrightnessChangedLocked() {
+ int brightness = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS, -1);
+
+ Vote vote = null;
+ boolean insideZone = isInsideZone(brightness, mAmbientLux);
+ if (insideZone) {
+ vote = Vote.forRefreshRates(mRefreshRateInZone, mRefreshRateInZone);
}
if (DEBUG) {
Slog.d(TAG, "Display brightness " + brightness + ", ambient lux " + mAmbientLux +
- (vote != null ? " 60hz only" : " no refresh rate limit"));
+ ", Vote " + vote);
}
updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote);
}
private void onScreenOn(boolean on) {
- // Not check mShouldObserveAmbientChange because Screen status receiver is registered
- // only when it is true.
if (mScreenOn != on) {
mScreenOn = on;
updateSensorStatus();
@@ -1020,6 +1068,13 @@ public class DisplayModeDirector {
}
}
+ private boolean isDefaultDisplayOn() {
+ final Display display = mContext.getSystemService(DisplayManager.class)
+ .getDisplay(Display.DEFAULT_DISPLAY);
+ return display.getState() != Display.STATE_OFF
+ && mContext.getSystemService(PowerManager.class).isInteractive();
+ }
+
private final class LightSensorEventListener implements SensorEventListener {
final private static int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS;
private float mLastSensorData;
@@ -1097,43 +1152,10 @@ public class DisplayModeDirector {
}
}
};
- };
-
- private final class ScreenStateReceiver extends BroadcastReceiver {
- final Context mContext;
- boolean mRegistered;
-
- public ScreenStateReceiver(Context context) {
- mContext = context;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- onScreenOn(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
- }
-
- public void register() {
- if (!mRegistered) {
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_SCREEN_OFF);
- filter.addAction(Intent.ACTION_SCREEN_ON);
- filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- mContext.registerReceiver(this, filter, null, mHandler);
- mRegistered = true;
- }
- }
-
- public void unregister() {
- if (mRegistered) {
- mContext.unregisterReceiver(this);
- mRegistered = false;
- }
- }
}
}
private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener {
-
public DeviceConfigDisplaySettings() {
}
@@ -1147,7 +1169,8 @@ public class DisplayModeDirector {
*/
public int[] getBrightnessThresholds() {
return getIntArrayProperty(
- DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_BRIGHTNESS_THRESHOLDS);
+ DisplayManager.DeviceConfig.
+ KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS);
}
/*
@@ -1155,7 +1178,8 @@ public class DisplayModeDirector {
*/
public int[] getAmbientThresholds() {
return getIntArrayProperty(
- DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_AMBIENT_THRESHOLDS);
+ DisplayManager.DeviceConfig.
+ KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS);
}
/*
@@ -1172,17 +1196,32 @@ public class DisplayModeDirector {
return defaultPeakRefreshRate;
}
+ public int getRefreshRateInZone() {
+ int defaultRefreshRateInZone = mContext.getResources().getInteger(
+ R.integer.config_defaultRefreshRateInZone);
+
+ int refreshRate = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_ZONE,
+ defaultRefreshRateInZone);
+
+ return refreshRate;
+ }
+
@Override
public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
int[] brightnessThresholds = getBrightnessThresholds();
int[] ambientThresholds = getAmbientThresholds();
Float defaultPeakRefreshRate = getDefaultPeakRefreshRate();
+ int refreshRateInZone = getRefreshRateInZone();
mHandler.obtainMessage(MSG_BRIGHTNESS_THRESHOLDS_CHANGED,
new Pair<int[], int[]>(brightnessThresholds, ambientThresholds))
.sendToTarget();
mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED,
defaultPeakRefreshRate).sendToTarget();
+ mHandler.obtainMessage(MSG_REFRESH_RATE_IN_ZONE_CHANGED, refreshRateInZone,
+ 0).sendToTarget();
}
private int[] getIntArrayProperty(String prop) {
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 7fb5b191a9b0..0bf43b6d1b9c 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -609,6 +609,9 @@ public final class ColorDisplayService extends SystemService {
@Override
public void onAnimationEnd(Animator animator) {
+ Slog.d(TAG, tintController.getClass().getSimpleName()
+ + " Animation cancelled: " + mIsCancelled
+ + " to matrix: " + TintController.matrixToString(to, 16));
if (!mIsCancelled) {
// Ensure final color matrix is set at the end of the animation. If the
// animation is cancelled then don't set the final color matrix so the new
@@ -1314,8 +1317,10 @@ public final class ColorDisplayService extends SystemService {
* Reset the CCT value for the display white balance transform to its default value.
*/
public boolean resetDisplayWhiteBalanceColorTemperature() {
- return setDisplayWhiteBalanceColorTemperature(getContext().getResources()
- .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault));
+ int temperatureDefault = getContext().getResources()
+ .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault);
+ Slog.d(TAG, "resetDisplayWhiteBalanceColorTemperature: " + temperatureDefault);
+ return setDisplayWhiteBalanceColorTemperature(temperatureDefault);
}
/**
diff --git a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
index d2c6cd9f1007..3f1c222ab520 100644
--- a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
+++ b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
@@ -149,8 +149,6 @@ final class DisplayWhiteBalanceTintController extends TintController {
cct = mTemperatureMax;
}
- Slog.d(ColorDisplayService.TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct);
-
synchronized (mLock) {
mCurrentColorTemperature = cct;
@@ -185,6 +183,9 @@ final class DisplayWhiteBalanceTintController extends TintController {
java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
}
+
+ Slog.d(ColorDisplayService.TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct
+ + " matrix = " + matrixToString(mMatrixDisplayWhiteBalance, 16));
}
@Override
@@ -225,28 +226,6 @@ final class DisplayWhiteBalanceTintController extends TintController {
}
}
- /**
- * Format a given matrix into a string.
- *
- * @param matrix the matrix to format
- * @param columns number of columns in the matrix
- */
- private String matrixToString(float[] matrix, int columns) {
- if (matrix == null || columns <= 0) {
- Slog.e(ColorDisplayService.TAG, "Invalid arguments when formatting matrix to string");
- return "";
- }
-
- final StringBuilder sb = new StringBuilder("");
- for (int i = 0; i < matrix.length; i++) {
- if (i % columns == 0) {
- sb.append("\n ");
- }
- sb.append(String.format("%9.6f", matrix[i]));
- }
- return sb.toString();
- }
-
private ColorSpace.Rgb makeRgbColorSpaceFromXYZ(float[] redGreenBlueXYZ, float[] whiteXYZ) {
return new ColorSpace.Rgb(
"Display Color Space",
diff --git a/services/core/java/com/android/server/display/color/TintController.java b/services/core/java/com/android/server/display/color/TintController.java
index b291c645027a..8d8b9b2af04e 100644
--- a/services/core/java/com/android/server/display/color/TintController.java
+++ b/services/core/java/com/android/server/display/color/TintController.java
@@ -18,6 +18,7 @@ package com.android.server.display.color;
import android.animation.ValueAnimator;
import android.content.Context;
+import android.util.Slog;
import java.io.PrintWriter;
@@ -95,4 +96,29 @@ abstract class TintController {
* Returns whether or not this transform type is available on this device.
*/
public abstract boolean isAvailable(Context context);
+
+ /**
+ * Format a given matrix into a string.
+ *
+ * @param matrix the matrix to format
+ * @param columns number of columns in the matrix
+ */
+ static String matrixToString(float[] matrix, int columns) {
+ if (matrix == null || columns <= 0) {
+ Slog.e(ColorDisplayService.TAG, "Invalid arguments when formatting matrix to string,"
+ + " matrix is null: " + (matrix == null)
+ + " columns: " + columns);
+ return "";
+ }
+
+ final StringBuilder sb = new StringBuilder("");
+ for (int i = 0; i < matrix.length; i++) {
+ if (i % columns == 0) {
+ sb.append("\n ");
+ }
+ sb.append(String.format("%9.6f", matrix[i]));
+ }
+ return sb.toString();
+ }
+
}
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
index 02ec10e2d49d..7b1f4c3222f3 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
@@ -95,6 +95,11 @@ public class DisplayWhiteBalanceController implements
// A piecewise linear relationship between high light brightness and high light bias.
private Spline.LinearSpline mHighLightAmbientBrightnessToBiasSpline;
+ private float mLatestAmbientColorTemperature;
+ private float mLatestAmbientBrightness;
+ private float mLatestLowLightBias;
+ private float mLatestHighLightBias;
+
/**
* @param brightnessSensor
* The sensor used to detect changes in the ambient brightness.
@@ -348,6 +353,7 @@ public class DisplayWhiteBalanceController implements
public void updateAmbientColorTemperature() {
final long time = System.currentTimeMillis();
float ambientColorTemperature = mColorTemperatureFilter.getEstimate(time);
+ mLatestAmbientColorTemperature = ambientColorTemperature;
if (mAmbientToDisplayColorTemperatureSpline != null && ambientColorTemperature != -1.0f) {
ambientColorTemperature =
@@ -355,6 +361,7 @@ public class DisplayWhiteBalanceController implements
}
float ambientBrightness = mBrightnessFilter.getEstimate(time);
+ mLatestAmbientBrightness = ambientBrightness;
if (ambientColorTemperature != -1.0f &&
mLowLightAmbientBrightnessToBiasSpline != null) {
@@ -362,6 +369,7 @@ public class DisplayWhiteBalanceController implements
ambientColorTemperature =
bias * ambientColorTemperature + (1.0f - bias)
* mLowLightAmbientColorTemperature;
+ mLatestLowLightBias = bias;
}
if (ambientColorTemperature != -1.0f &&
mHighLightAmbientBrightnessToBiasSpline != null) {
@@ -369,6 +377,7 @@ public class DisplayWhiteBalanceController implements
ambientColorTemperature =
(1.0f - bias) * ambientColorTemperature + bias
* mHighLightAmbientColorTemperature;
+ mLatestHighLightBias = bias;
}
if (mAmbientColorTemperatureOverride != -1.0f) {
@@ -426,6 +435,11 @@ public class DisplayWhiteBalanceController implements
}
mPendingAmbientColorTemperature = -1.0f;
mAmbientColorTemperatureHistory.add(mAmbientColorTemperature);
+ Slog.d(TAG, "Display cct: " + mAmbientColorTemperature
+ + " Latest ambient cct: " + mLatestAmbientColorTemperature
+ + " Latest ambient lux: " + mLatestAmbientBrightness
+ + " Latest low light bias: " + mLatestLowLightBias
+ + " Latest high light bias: " + mLatestHighLightBias);
mColorDisplayServiceInternal.setDisplayWhiteBalanceColorTemperature(
(int) mAmbientColorTemperature);
mLastAmbientColorTemperature = mAmbientColorTemperature;
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 9782f30d3074..259527a5f217 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -79,7 +79,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
S extends AbstractPerUserSystemService<S, M>> extends SystemService {
/** On a package update, does not refresh the per-user service in the cache. */
- public static final int PACKAGE_UPDATE_POLICY_NO_REFRESH = 0;
+ public static final int PACKAGE_UPDATE_POLICY_NO_REFRESH = 0x00000001;
/**
* On a package update, removes any existing per-user services in the cache.
@@ -87,20 +87,40 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
* <p>This does not immediately recreate these services. It is assumed they will be recreated
* for the next user request.
*/
- public static final int PACKAGE_UPDATE_POLICY_REFRESH_LAZY = 1;
+ public static final int PACKAGE_UPDATE_POLICY_REFRESH_LAZY = 0x00000002;
/**
* On a package update, removes and recreates any existing per-user services in the cache.
*/
- public static final int PACKAGE_UPDATE_POLICY_REFRESH_EAGER = 2;
+ public static final int PACKAGE_UPDATE_POLICY_REFRESH_EAGER = 0x00000004;
- @IntDef(flag = true, prefix = { "PACKAGE_UPDATE_POLICY_" }, value = {
+ /** On a package restart, does not refresh the per-user service in the cache. */
+ public static final int PACKAGE_RESTART_POLICY_NO_REFRESH = 0x00000010;
+
+ /**
+ * On a package restart, removes any existing per-user services in the cache.
+ *
+ * <p>This does not immediately recreate these services. It is assumed they will be recreated
+ * for the next user request.
+ */
+ public static final int PACKAGE_RESTART_POLICY_REFRESH_LAZY = 0x00000020;
+
+ /**
+ * On a package restart, removes and recreates any existing per-user services in the cache.
+ */
+ public static final int PACKAGE_RESTART_POLICY_REFRESH_EAGER = 0x00000040;
+
+ @IntDef(flag = true, prefix = { "PACKAGE_" }, value = {
PACKAGE_UPDATE_POLICY_NO_REFRESH,
PACKAGE_UPDATE_POLICY_REFRESH_LAZY,
- PACKAGE_UPDATE_POLICY_REFRESH_EAGER
+ PACKAGE_UPDATE_POLICY_REFRESH_EAGER,
+ PACKAGE_RESTART_POLICY_NO_REFRESH,
+ PACKAGE_RESTART_POLICY_REFRESH_LAZY,
+ PACKAGE_RESTART_POLICY_REFRESH_EAGER
})
+
@Retention(RetentionPolicy.SOURCE)
- public @interface PackageUpdatePolicy {}
+ public @interface ServicePackagePolicyFlags {}
/**
* Log tag
@@ -153,12 +173,10 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
private final SparseArray<S> mServicesCache = new SparseArray<>();
/**
- * Whether the per-user service should be removed from the cache when its apk is updated.
- *
- * <p>One of {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH},
- * {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY} or {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER}.
+ * Value that determines whether the per-user service should be removed from the cache when its
+ * apk is updated or restarted.
*/
- private final @PackageUpdatePolicy int mPackageUpdatePolicy;
+ private final @ServicePackagePolicyFlags int mServicePackagePolicyFlags;
/**
* Name of the service packages whose APK are being updated, keyed by user id.
@@ -184,11 +202,11 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
@Nullable ServiceNameResolver serviceNameResolver,
@Nullable String disallowProperty) {
this(context, serviceNameResolver, disallowProperty,
- /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_REFRESH_LAZY);
+ PACKAGE_UPDATE_POLICY_REFRESH_LAZY | PACKAGE_RESTART_POLICY_REFRESH_LAZY);
}
/**
- * Full constructor.
+ * Full Constructor.
*
* @param context system context.
* @param serviceNameResolver resolver for
@@ -197,19 +215,32 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
* @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that
* disables the service. <b>NOTE: </b> you'll also need to add it to
* {@code UserRestrictionsUtils.USER_RESTRICTIONS}.
- * @param packageUpdatePolicy when {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY}, the
- * {@link AbstractPerUserSystemService} is removed from the cache when the service
- * package is updated; when {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER}, the
- * {@link AbstractPerUserSystemService} is removed from the cache and immediately
- * re-added when the service package is updated; when
- * {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH}, the service is untouched during the update.
+ * @param servicePackagePolicyFlags a combination of
+ * {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH},
+ * {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY},
+ * {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER},
+ * {@link #PACKAGE_RESTART_POLICY_NO_REFRESH},
+ * {@link #PACKAGE_RESTART_POLICY_REFRESH_LAZY} or
+ * {@link #PACKAGE_RESTART_POLICY_REFRESH_EAGER}
*/
protected AbstractMasterSystemService(@NonNull Context context,
- @Nullable ServiceNameResolver serviceNameResolver,
- @Nullable String disallowProperty, @PackageUpdatePolicy int packageUpdatePolicy) {
+ @Nullable ServiceNameResolver serviceNameResolver, @Nullable String disallowProperty,
+ @ServicePackagePolicyFlags int servicePackagePolicyFlags) {
super(context);
- mPackageUpdatePolicy = packageUpdatePolicy;
+ final int updatePolicyMask = PACKAGE_UPDATE_POLICY_NO_REFRESH
+ | PACKAGE_UPDATE_POLICY_REFRESH_LAZY | PACKAGE_UPDATE_POLICY_REFRESH_EAGER;
+ if ((servicePackagePolicyFlags & updatePolicyMask) == 0) {
+ // If the package update policy is not set, add the default flag
+ servicePackagePolicyFlags |= PACKAGE_UPDATE_POLICY_REFRESH_LAZY;
+ }
+ final int restartPolicyMask = PACKAGE_RESTART_POLICY_NO_REFRESH
+ | PACKAGE_RESTART_POLICY_REFRESH_LAZY | PACKAGE_RESTART_POLICY_REFRESH_EAGER;
+ if ((servicePackagePolicyFlags & restartPolicyMask) == 0) {
+ // If the package restart policy is not set, add the default flag
+ servicePackagePolicyFlags |= PACKAGE_RESTART_POLICY_REFRESH_LAZY;
+ }
+ mServicePackagePolicyFlags = servicePackagePolicyFlags;
mServiceNameResolver = serviceNameResolver;
if (mServiceNameResolver != null) {
@@ -606,6 +637,20 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
}
/**
+ * Called after the package data that provides the service for the given user is cleared.
+ */
+ protected void onServicePackageDataClearedLocked(@UserIdInt int userId) {
+ if (verbose) Slog.v(mTag, "onServicePackageDataCleared(" + userId + ")");
+ }
+
+ /**
+ * Called after the package that provides the service for the given user is restarted.
+ */
+ protected void onServicePackageRestartedLocked(@UserIdInt int userId) {
+ if (verbose) Slog.v(mTag, "onServicePackageRestarted(" + userId + ")");
+ }
+
+ /**
* Called after the service is removed from the cache.
*/
@SuppressWarnings("unused")
@@ -677,7 +722,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
final int size = mServicesCache.size();
pw.print(prefix); pw.print("Debug: "); pw.print(realDebug);
pw.print(" Verbose: "); pw.println(realVerbose);
- pw.print("Refresh on package update: "); pw.println(mPackageUpdatePolicy);
+ pw.print("Package policy flags: "); pw.println(mServicePackagePolicyFlags);
if (mUpdatingPackageNames != null) {
pw.print("Packages being updated: "); pw.println(mUpdatingPackageNames);
}
@@ -733,7 +778,12 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
}
mUpdatingPackageNames.put(userId, packageName);
onServicePackageUpdatingLocked(userId);
- if (mPackageUpdatePolicy != PACKAGE_UPDATE_POLICY_NO_REFRESH) {
+ if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_NO_REFRESH) != 0) {
+ if (debug) {
+ Slog.d(mTag, "Holding service for user " + userId + " while package "
+ + activePackageName + " is being updated");
+ }
+ } else {
if (debug) {
Slog.d(mTag, "Removing service for user " + userId
+ " because package " + activePackageName
@@ -741,18 +791,14 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
}
removeCachedServiceLocked(userId);
- if (mPackageUpdatePolicy == PACKAGE_UPDATE_POLICY_REFRESH_EAGER) {
+ if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_REFRESH_EAGER)
+ != 0) {
if (debug) {
Slog.d(mTag, "Eagerly recreating service for user "
+ userId);
}
getServiceForUserLocked(userId);
}
- } else {
- if (debug) {
- Slog.d(mTag, "Holding service for user " + userId + " while package "
- + activePackageName + " is being updated");
- }
}
}
}
@@ -804,7 +850,13 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
if (!doit) {
return true;
}
- removeCachedServiceLocked(getChangingUserId());
+ final String action = intent.getAction();
+ final int userId = getChangingUserId();
+ if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
+ handleActiveServiceRestartedLocked(activePackageName, userId);
+ } else {
+ removeCachedServiceLocked(userId);
+ }
} else {
handlePackageUpdateLocked(pkg);
}
@@ -813,6 +865,23 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
return false;
}
+ @Override
+ public void onPackageDataCleared(String packageName, int uid) {
+ if (verbose) Slog.v(mTag, "onPackageDataCleared(): " + packageName);
+ final int userId = getChangingUserId();
+ synchronized (mLock) {
+ final S service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ final ComponentName componentName = service.getServiceComponentName();
+ if (componentName != null) {
+ if (packageName.equals(componentName.getPackageName())) {
+ onServicePackageDataClearedLocked(userId);
+ }
+ }
+ }
+ }
+ }
+
private void handleActiveServiceRemoved(@UserIdInt int userId) {
synchronized (mLock) {
removeCachedServiceLocked(userId);
@@ -824,6 +893,31 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
}
}
+ private void handleActiveServiceRestartedLocked(String activePackageName,
+ @UserIdInt int userId) {
+ if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_NO_REFRESH) != 0) {
+ if (debug) {
+ Slog.d(mTag, "Holding service for user " + userId + " while package "
+ + activePackageName + " is being restarted");
+ }
+ } else {
+ if (debug) {
+ Slog.d(mTag, "Removing service for user " + userId
+ + " because package " + activePackageName
+ + " is being restarted");
+ }
+ removeCachedServiceLocked(userId);
+
+ if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_REFRESH_EAGER) != 0) {
+ if (debug) {
+ Slog.d(mTag, "Eagerly recreating service for user " + userId);
+ }
+ getServiceForUserLocked(userId);
+ }
+ }
+ onServicePackageRestartedLocked(userId);
+ }
+
private String getActiveServicePackageNameLocked() {
final int userId = getChangingUserId();
final S service = peekServiceForUserLocked(userId);
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index c312b76cc463..181a43549313 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1459,7 +1459,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
info.mSvCarrierFreqs);
// Log CN0 as part of GNSS metrics
- mGnssMetrics.logCn0(info.mCn0s, info.mSvCount);
+ mGnssMetrics.logCn0(info.mCn0s, info.mSvCount, info.mSvCarrierFreqs);
if (VERBOSE) {
Log.v(TAG, "SV count: " + info.mSvCount);
@@ -1510,6 +1510,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE);
}
+
+ mGnssMetrics.logSvStatus(info.mSvCount, info.mSvidWithFlags, info.mSvCarrierFreqs);
}
@NativeEntryPoint
diff --git a/services/core/java/com/android/server/notification/BubbleExtractor.java b/services/core/java/com/android/server/notification/BubbleExtractor.java
index 358bdb90f6d3..e59bf1642ba8 100644
--- a/services/core/java/com/android/server/notification/BubbleExtractor.java
+++ b/services/core/java/com/android/server/notification/BubbleExtractor.java
@@ -41,10 +41,9 @@ public class BubbleExtractor implements NotificationSignalExtractor {
if (DBG) Slog.d(TAG, "missing config");
return null;
}
- boolean userWantsBubbles = mConfig.bubblesEnabled(record.sbn.getUser());
boolean appCanShowBubble =
mConfig.areBubblesAllowed(record.sbn.getPackageName(), record.sbn.getUid());
- if (!userWantsBubbles || !appCanShowBubble) {
+ if (!mConfig.bubblesEnabled() || !appCanShowBubble) {
record.setAllowBubble(false);
} else {
if (record.getChannel() != null) {
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 4a6eb276bd02..4828bbfff676 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -196,18 +196,20 @@ abstract public class ManagedServices {
public void dump(PrintWriter pw, DumpFilter filter) {
pw.println(" Allowed " + getCaption() + "s:");
- final int N = mApproved.size();
- for (int i = 0 ; i < N; i++) {
- final int userId = mApproved.keyAt(i);
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
- if (approvedByType != null) {
- final int M = approvedByType.size();
- for (int j = 0; j < M; j++) {
- final boolean isPrimary = approvedByType.keyAt(j);
- final ArraySet<String> approved = approvedByType.valueAt(j);
- if (approvedByType != null && approvedByType.size() > 0) {
- pw.println(" " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
- + " (user: " + userId + " isPrimary: " + isPrimary + ")");
+ synchronized (mApproved) {
+ final int N = mApproved.size();
+ for (int i = 0; i < N; i++) {
+ final int userId = mApproved.keyAt(i);
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
+ if (approvedByType != null) {
+ final int M = approvedByType.size();
+ for (int j = 0; j < M; j++) {
+ final boolean isPrimary = approvedByType.keyAt(j);
+ final ArraySet<String> approved = approvedByType.valueAt(j);
+ if (approvedByType != null && approvedByType.size() > 0) {
+ pw.println(" " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
+ + " (user: " + userId + " isPrimary: " + isPrimary + ")");
+ }
}
}
}
@@ -240,23 +242,25 @@ abstract public class ManagedServices {
public void dump(ProtoOutputStream proto, DumpFilter filter) {
proto.write(ManagedServicesProto.CAPTION, getCaption());
- final int N = mApproved.size();
- for (int i = 0 ; i < N; i++) {
- final int userId = mApproved.keyAt(i);
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
- if (approvedByType != null) {
- final int M = approvedByType.size();
- for (int j = 0; j < M; j++) {
- final boolean isPrimary = approvedByType.keyAt(j);
- final ArraySet<String> approved = approvedByType.valueAt(j);
- if (approvedByType != null && approvedByType.size() > 0) {
- final long sToken = proto.start(ManagedServicesProto.APPROVED);
- for (String s : approved) {
- proto.write(ServiceProto.NAME, s);
+ synchronized (mApproved) {
+ final int N = mApproved.size();
+ for (int i = 0; i < N; i++) {
+ final int userId = mApproved.keyAt(i);
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
+ if (approvedByType != null) {
+ final int M = approvedByType.size();
+ for (int j = 0; j < M; j++) {
+ final boolean isPrimary = approvedByType.keyAt(j);
+ final ArraySet<String> approved = approvedByType.valueAt(j);
+ if (approvedByType != null && approvedByType.size() > 0) {
+ final long sToken = proto.start(ManagedServicesProto.APPROVED);
+ for (String s : approved) {
+ proto.write(ServiceProto.NAME, s);
+ }
+ proto.write(ServiceProto.USER_ID, userId);
+ proto.write(ServiceProto.IS_PRIMARY, isPrimary);
+ proto.end(sToken);
}
- proto.write(ServiceProto.USER_ID, userId);
- proto.write(ServiceProto.IS_PRIMARY, isPrimary);
- proto.end(sToken);
}
}
}
@@ -315,33 +319,36 @@ abstract public class ManagedServices {
trimApprovedListsAccordingToInstalledServices(userId);
}
- final int N = mApproved.size();
- for (int i = 0 ; i < N; i++) {
- final int approvedUserId = mApproved.keyAt(i);
- if (forBackup && approvedUserId != userId) {
- continue;
- }
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
- if (approvedByType != null) {
- final int M = approvedByType.size();
- for (int j = 0; j < M; j++) {
- final boolean isPrimary = approvedByType.keyAt(j);
- final Set<String> approved = approvedByType.valueAt(j);
- if (approved != null) {
- String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
- out.startTag(null, TAG_MANAGED_SERVICES);
- out.attribute(null, ATT_APPROVED_LIST, allowedItems);
- out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
- out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
- writeExtraAttributes(out, approvedUserId);
- out.endTag(null, TAG_MANAGED_SERVICES);
-
- if (!forBackup && isPrimary) {
- // Also write values to settings, for observers who haven't migrated yet
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- getConfig().secureSettingName, allowedItems, approvedUserId);
- }
+ synchronized (mApproved) {
+ final int N = mApproved.size();
+ for (int i = 0; i < N; i++) {
+ final int approvedUserId = mApproved.keyAt(i);
+ if (forBackup && approvedUserId != userId) {
+ continue;
+ }
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
+ if (approvedByType != null) {
+ final int M = approvedByType.size();
+ for (int j = 0; j < M; j++) {
+ final boolean isPrimary = approvedByType.keyAt(j);
+ final Set<String> approved = approvedByType.valueAt(j);
+ if (approved != null) {
+ String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
+ out.startTag(null, TAG_MANAGED_SERVICES);
+ out.attribute(null, ATT_APPROVED_LIST, allowedItems);
+ out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
+ out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
+ writeExtraAttributes(out, approvedUserId);
+ out.endTag(null, TAG_MANAGED_SERVICES);
+
+ if (!forBackup && isPrimary) {
+ // Also write values to settings, for observers who haven't migrated yet
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ getConfig().secureSettingName, allowedItems,
+ approvedUserId);
+ }
+ }
}
}
}
@@ -440,23 +447,25 @@ abstract public class ManagedServices {
if (TextUtils.isEmpty(approved)) {
approved = "";
}
- ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
- if (approvedByType == null) {
- approvedByType = new ArrayMap<>();
- mApproved.put(userId, approvedByType);
- }
+ synchronized (mApproved) {
+ ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
+ if (approvedByType == null) {
+ approvedByType = new ArrayMap<>();
+ mApproved.put(userId, approvedByType);
+ }
- ArraySet<String> approvedList = approvedByType.get(isPrimary);
- if (approvedList == null) {
- approvedList = new ArraySet<>();
- approvedByType.put(isPrimary, approvedList);
- }
+ ArraySet<String> approvedList = approvedByType.get(isPrimary);
+ if (approvedList == null) {
+ approvedList = new ArraySet<>();
+ approvedByType.put(isPrimary, approvedList);
+ }
- String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
- for (String pkgOrComponent : approvedArray) {
- String approvedItem = getApprovedValue(pkgOrComponent);
- if (approvedItem != null) {
- approvedList.add(approvedItem);
+ String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
+ for (String pkgOrComponent : approvedArray) {
+ String approvedItem = getApprovedValue(pkgOrComponent);
+ if (approvedItem != null) {
+ approvedList.add(approvedItem);
+ }
}
}
}
@@ -469,23 +478,25 @@ abstract public class ManagedServices {
boolean isPrimary, boolean enabled) {
Slog.i(TAG,
(enabled ? " Allowing " : "Disallowing ") + mConfig.caption + " " + pkgOrComponent);
- ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
- if (allowedByType == null) {
- allowedByType = new ArrayMap<>();
- mApproved.put(userId, allowedByType);
- }
- ArraySet<String> approved = allowedByType.get(isPrimary);
- if (approved == null) {
- approved = new ArraySet<>();
- allowedByType.put(isPrimary, approved);
- }
- String approvedItem = getApprovedValue(pkgOrComponent);
-
- if (approvedItem != null) {
- if (enabled) {
- approved.add(approvedItem);
- } else {
- approved.remove(approvedItem);
+ synchronized (mApproved) {
+ ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
+ if (allowedByType == null) {
+ allowedByType = new ArrayMap<>();
+ mApproved.put(userId, allowedByType);
+ }
+ ArraySet<String> approved = allowedByType.get(isPrimary);
+ if (approved == null) {
+ approved = new ArraySet<>();
+ allowedByType.put(isPrimary, approved);
+ }
+ String approvedItem = getApprovedValue(pkgOrComponent);
+
+ if (approvedItem != null) {
+ if (enabled) {
+ approved.add(approvedItem);
+ } else {
+ approved.remove(approvedItem);
+ }
}
}
@@ -504,22 +515,26 @@ abstract public class ManagedServices {
}
protected String getApproved(int userId, boolean primary) {
- final ArrayMap<Boolean, ArraySet<String>> allowedByType =
- mApproved.getOrDefault(userId, new ArrayMap<>());
- ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
- return String.join(ENABLED_SERVICES_SEPARATOR, approved);
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
+ return String.join(ENABLED_SERVICES_SEPARATOR, approved);
+ }
}
protected List<ComponentName> getAllowedComponents(int userId) {
final List<ComponentName> allowedComponents = new ArrayList<>();
- final ArrayMap<Boolean, ArraySet<String>> allowedByType =
- mApproved.getOrDefault(userId, new ArrayMap<>());
- for (int i = 0; i < allowedByType.size(); i++) {
- final ArraySet<String> allowed = allowedByType.valueAt(i);
- for (int j = 0; j < allowed.size(); j++) {
- ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j));
- if (cn != null) {
- allowedComponents.add(cn);
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ for (int i = 0; i < allowedByType.size(); i++) {
+ final ArraySet<String> allowed = allowedByType.valueAt(i);
+ for (int j = 0; j < allowed.size(); j++) {
+ ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j));
+ if (cn != null) {
+ allowedComponents.add(cn);
+ }
}
}
}
@@ -528,14 +543,16 @@ abstract public class ManagedServices {
protected List<String> getAllowedPackages(int userId) {
final List<String> allowedPackages = new ArrayList<>();
- final ArrayMap<Boolean, ArraySet<String>> allowedByType =
- mApproved.getOrDefault(userId, new ArrayMap<>());
- for (int i = 0; i < allowedByType.size(); i++) {
- final ArraySet<String> allowed = allowedByType.valueAt(i);
- for (int j = 0; j < allowed.size(); j++) {
- String pkgName = getPackageName(allowed.valueAt(j));
- if (!TextUtils.isEmpty(pkgName)) {
- allowedPackages.add(pkgName);
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ for (int i = 0; i < allowedByType.size(); i++) {
+ final ArraySet<String> allowed = allowedByType.valueAt(i);
+ for (int j = 0; j < allowed.size(); j++) {
+ String pkgName = getPackageName(allowed.valueAt(j));
+ if (!TextUtils.isEmpty(pkgName)) {
+ allowedPackages.add(pkgName);
+ }
}
}
}
@@ -543,12 +560,14 @@ abstract public class ManagedServices {
}
protected boolean isPackageOrComponentAllowed(String pkgOrComponent, int userId) {
- ArrayMap<Boolean, ArraySet<String>> allowedByType =
- mApproved.getOrDefault(userId, new ArrayMap<>());
- for (int i = 0; i < allowedByType.size(); i++) {
- ArraySet<String> allowed = allowedByType.valueAt(i);
- if (allowed.contains(pkgOrComponent)) {
- return true;
+ synchronized (mApproved) {
+ ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ for (int i = 0; i < allowedByType.size(); i++) {
+ ArraySet<String> allowed = allowedByType.valueAt(i);
+ if (allowed.contains(pkgOrComponent)) {
+ return true;
+ }
}
}
return false;
@@ -558,19 +577,21 @@ abstract public class ManagedServices {
if (pkg == null) {
return false;
}
- ArrayMap<Boolean, ArraySet<String>> allowedByType =
- mApproved.getOrDefault(userId, new ArrayMap<>());
- for (int i = 0; i < allowedByType.size(); i++) {
- ArraySet<String> allowed = allowedByType.valueAt(i);
- for (String allowedEntry : allowed) {
- ComponentName component = ComponentName.unflattenFromString(allowedEntry);
- if (component != null) {
- if (pkg.equals(component.getPackageName())) {
- return true;
- }
- } else {
- if (pkg.equals(allowedEntry)) {
- return true;
+ synchronized (mApproved) {
+ ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ for (int i = 0; i < allowedByType.size(); i++) {
+ ArraySet<String> allowed = allowedByType.valueAt(i);
+ for (String allowedEntry : allowed) {
+ ComponentName component = ComponentName.unflattenFromString(allowedEntry);
+ if (component != null) {
+ if (pkg.equals(component.getPackageName())) {
+ return true;
+ }
+ } else {
+ if (pkg.equals(allowedEntry)) {
+ return true;
+ }
}
}
}
@@ -616,7 +637,9 @@ abstract public class ManagedServices {
public void onUserRemoved(int user) {
Slog.i(TAG, "Removing approved services for removed user " + user);
- mApproved.remove(user);
+ synchronized (mApproved) {
+ mApproved.remove(user);
+ }
rebindServices(true, user);
}
@@ -797,14 +820,16 @@ abstract public class ManagedServices {
protected Set<String> getAllowedPackages() {
final Set<String> allowedPackages = new ArraySet<>();
- for (int k = 0; k < mApproved.size(); k++) {
- ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
- for (int i = 0; i < allowedByType.size(); i++) {
- final ArraySet<String> allowed = allowedByType.valueAt(i);
- for (int j = 0; j < allowed.size(); j++) {
- String pkgName = getPackageName(allowed.valueAt(j));
- if (!TextUtils.isEmpty(pkgName)) {
- allowedPackages.add(pkgName);
+ synchronized (mApproved) {
+ for (int k = 0; k < mApproved.size(); k++) {
+ ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
+ for (int i = 0; i < allowedByType.size(); i++) {
+ final ArraySet<String> allowed = allowedByType.valueAt(i);
+ for (int j = 0; j < allowed.size(); j++) {
+ String pkgName = getPackageName(allowed.valueAt(j));
+ if (!TextUtils.isEmpty(pkgName)) {
+ allowedPackages.add(pkgName);
+ }
}
}
}
@@ -813,22 +838,24 @@ abstract public class ManagedServices {
}
private void trimApprovedListsAccordingToInstalledServices(int userId) {
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
- if (approvedByType == null) {
- return;
- }
- for (int i = 0; i < approvedByType.size(); i++) {
- final ArraySet<String> approved = approvedByType.valueAt(i);
- for (int j = approved.size() - 1; j >= 0; j--) {
- final String approvedPackageOrComponent = approved.valueAt(j);
- if (!isValidEntry(approvedPackageOrComponent, userId)){
- approved.removeAt(j);
- Slog.v(TAG, "Removing " + approvedPackageOrComponent
- + " from approved list; no matching services found");
- } else {
- if (DEBUG) {
- Slog.v(TAG, "Keeping " + approvedPackageOrComponent
- + " on approved list; matching services found");
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
+ if (approvedByType == null) {
+ return;
+ }
+ for (int i = 0; i < approvedByType.size(); i++) {
+ final ArraySet<String> approved = approvedByType.valueAt(i);
+ for (int j = approved.size() - 1; j >= 0; j--) {
+ final String approvedPackageOrComponent = approved.valueAt(j);
+ if (!isValidEntry(approvedPackageOrComponent, userId)) {
+ approved.removeAt(j);
+ Slog.v(TAG, "Removing " + approvedPackageOrComponent
+ + " from approved list; no matching services found");
+ } else {
+ if (DEBUG) {
+ Slog.v(TAG, "Keeping " + approvedPackageOrComponent
+ + " on approved list; matching services found");
+ }
}
}
}
@@ -837,20 +864,23 @@ abstract public class ManagedServices {
private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, String pkg) {
boolean removed = false;
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(uninstalledUserId);
- if (approvedByType != null) {
- int M = approvedByType.size();
- for (int j = 0; j < M; j++) {
- final ArraySet<String> approved = approvedByType.valueAt(j);
- int O = approved.size();
- for (int k = O - 1; k >= 0; k--) {
- final String packageOrComponent = approved.valueAt(k);
- final String packageName = getPackageName(packageOrComponent);
- if (TextUtils.equals(pkg, packageName)) {
- approved.removeAt(k);
- if (DEBUG) {
- Slog.v(TAG, "Removing " + packageOrComponent
- + " from approved list; uninstalled");
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(
+ uninstalledUserId);
+ if (approvedByType != null) {
+ int M = approvedByType.size();
+ for (int j = 0; j < M; j++) {
+ final ArraySet<String> approved = approvedByType.valueAt(j);
+ int O = approved.size();
+ for (int k = O - 1; k >= 0; k--) {
+ final String packageOrComponent = approved.valueAt(k);
+ final String packageName = getPackageName(packageOrComponent);
+ if (TextUtils.equals(pkg, packageName)) {
+ approved.removeAt(k);
+ if (DEBUG) {
+ Slog.v(TAG, "Removing " + packageOrComponent
+ + " from approved list; uninstalled");
+ }
}
}
}
@@ -887,17 +917,19 @@ abstract public class ManagedServices {
for (int i = 0; i < nUserIds; ++i) {
final int userId = userIds.get(i);
- final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
- if (approvedLists != null) {
- final int N = approvedLists.size();
- for (int j = 0; j < N; j++) {
- ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
- if (approvedByUser == null) {
- approvedByUser = new ArraySet<>();
- componentsByUser.put(userId, approvedByUser);
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
+ if (approvedLists != null) {
+ final int N = approvedLists.size();
+ for (int j = 0; j < N; j++) {
+ ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
+ if (approvedByUser == null) {
+ approvedByUser = new ArraySet<>();
+ componentsByUser.put(userId, approvedByUser);
+ }
+ approvedByUser.addAll(
+ loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
}
- approvedByUser.addAll(
- loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index faac78d68879..655b9ac10b84 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -91,6 +91,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
+import static com.android.server.notification.PreferencesHelper.DEFAULT_ALLOW_BUBBLE;
import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
@@ -466,6 +467,8 @@ public class NotificationManagerService extends SystemService {
private MetricsLogger mMetricsLogger;
private TriPredicate<String, Integer, String> mAllowedManagedServicePackages;
+ private final SavePolicyFileRunnable mSavePolicyFile = new SavePolicyFileRunnable();
+
private static class Archive {
final int mBufferSize;
final ArrayDeque<StatusBarNotification> mBuffer;
@@ -659,7 +662,14 @@ public class NotificationManagerService extends SystemService {
@VisibleForTesting
protected void handleSavePolicyFile() {
- IoThread.getHandler().post(() -> {
+ if (!IoThread.getHandler().hasCallbacks(mSavePolicyFile)) {
+ IoThread.getHandler().post(mSavePolicyFile);
+ }
+ }
+
+ private final class SavePolicyFileRunnable implements Runnable {
+ @Override
+ public void run() {
if (DBG) Slog.d(TAG, "handleSavePolicyFile");
synchronized (mPolicyFile) {
final FileOutputStream stream;
@@ -679,7 +689,7 @@ public class NotificationManagerService extends SystemService {
}
}
BackupManager.dataChanged(getContext().getPackageName());
- });
+ }
}
private void writePolicyXml(OutputStream stream, boolean forBackup, int userId)
@@ -1371,7 +1381,9 @@ public class NotificationManagerService extends SystemService {
private final class SettingsObserver extends ContentObserver {
private final Uri NOTIFICATION_BADGING_URI
= Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
- private final Uri NOTIFICATION_BUBBLES_URI
+ private final Uri NOTIFICATION_BUBBLES_URI_GLOBAL
+ = Settings.Global.getUriFor(Settings.Global.NOTIFICATION_BUBBLES);
+ private final Uri NOTIFICATION_BUBBLES_URI_SECURE
= Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BUBBLES);
private final Uri NOTIFICATION_LIGHT_PULSE_URI
= Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
@@ -1390,7 +1402,9 @@ public class NotificationManagerService extends SystemService {
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
false, this, UserHandle.USER_ALL);
- resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI,
+ resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI_GLOBAL,
+ false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI_SECURE,
false, this, UserHandle.USER_ALL);
update(null);
}
@@ -1417,9 +1431,41 @@ public class NotificationManagerService extends SystemService {
if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
mPreferencesHelper.updateBadgingEnabled();
}
- if (uri == null || NOTIFICATION_BUBBLES_URI.equals(uri)) {
+ // In QPR we moved the setting to Global rather than Secure so that the setting
+ // applied to work profiles. Unfortunately we need to maintain both to pass CTS without
+ // a change to CTS outside of a normal letter release.
+ if (uri == null || NOTIFICATION_BUBBLES_URI_GLOBAL.equals(uri)) {
+ syncBubbleSettings(resolver, NOTIFICATION_BUBBLES_URI_GLOBAL);
mPreferencesHelper.updateBubblesEnabled();
}
+ if (NOTIFICATION_BUBBLES_URI_SECURE.equals(uri)) {
+ syncBubbleSettings(resolver, NOTIFICATION_BUBBLES_URI_SECURE);
+ }
+ }
+
+ private void syncBubbleSettings(ContentResolver resolver, Uri settingToFollow) {
+ boolean followSecureSetting = settingToFollow.equals(NOTIFICATION_BUBBLES_URI_SECURE);
+
+ int secureSettingValue = Settings.Secure.getInt(resolver,
+ Settings.Secure.NOTIFICATION_BUBBLES, DEFAULT_ALLOW_BUBBLE ? 1 : 0);
+ int globalSettingValue = Settings.Global.getInt(resolver,
+ Settings.Global.NOTIFICATION_BUBBLES, DEFAULT_ALLOW_BUBBLE ? 1 : 0);
+
+ if (globalSettingValue == secureSettingValue) {
+ return;
+ }
+
+ if (followSecureSetting) {
+ // Global => secure
+ Settings.Global.putInt(resolver,
+ Settings.Global.NOTIFICATION_BUBBLES,
+ secureSettingValue);
+ } else {
+ // Secure => Global
+ Settings.Secure.putInt(resolver,
+ Settings.Secure.NOTIFICATION_BADGING,
+ globalSettingValue);
+ }
}
}
@@ -1837,6 +1883,7 @@ public class NotificationManagerService extends SystemService {
}
if (properties.getKeyset()
.contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) {
+ mAssistants.allowAdjustmentType(Adjustment.KEY_IMPORTANCE);
mAssistants.resetDefaultAssistantsIfNecessary();
}
});
@@ -2269,7 +2316,7 @@ public class NotificationManagerService extends SystemService {
final int callingUid = Binder.getCallingUid();
final boolean isSystemToast = isCallerSystemOrPhone()
|| PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg);
- final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
+ final boolean isPackageSuspended = isPackagePaused(pkg);
final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg,
callingUid);
@@ -2418,9 +2465,25 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ public void silenceNotificationSound() {
+ checkCallerIsSystem();
+
+ mNotificationDelegate.clearEffects();
+ }
+
+ @Override
public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
+ synchronized (mNotificationLock) {
+ boolean wasEnabled = mPreferencesHelper.getImportance(pkg, uid)
+ != NotificationManager.IMPORTANCE_NONE;
+
+ if (wasEnabled == enabled) {
+ return;
+ }
+ }
+
mPreferencesHelper.setEnabled(pkg, uid, enabled);
mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
.setType(MetricsEvent.TYPE_ACTION)
@@ -4107,17 +4170,7 @@ public class NotificationManagerService extends SystemService {
Preconditions.checkNotNull(pkg);
checkCallerIsSameApp(pkg);
- boolean isPaused;
-
- final PackageManagerInternal pmi = LocalServices.getService(
- PackageManagerInternal.class);
- int flags = pmi.getDistractingPackageRestrictions(
- pkg, Binder.getCallingUserHandle().getIdentifier());
- isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0);
-
- isPaused |= isPackageSuspendedForUser(pkg, Binder.getCallingUid());
-
- return isPaused;
+ return isPackagePausedOrSuspended(pkg, Binder.getCallingUid());
}
private void verifyPrivilegedListener(INotificationListener token, UserHandle user,
@@ -4830,47 +4883,112 @@ public class NotificationManagerService extends SystemService {
} else {
notification.flags &= ~FLAG_BUBBLE;
}
+ // Is the app in the foreground?
+ final boolean appIsForeground =
+ mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
+ Notification.BubbleMetadata metadata = notification.getBubbleMetadata();
+ if (!appIsForeground && metadata != null) {
+ // Remove any flags that only work when foregrounded
+ int flags = metadata.getFlags();
+ flags &= ~Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
+ flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+ metadata.setFlags(flags);
+ }
}
/**
- * @return whether the provided notification record is allowed to be represented as a bubble.
+ * @return whether the provided notification record is allowed to be represented as a bubble,
+ * accounting for user choice & policy.
*/
private boolean isNotificationAppropriateToBubble(NotificationRecord r, String pkg, int userId,
NotificationRecord oldRecord) {
Notification notification = r.getNotification();
- Notification.BubbleMetadata metadata = notification.getBubbleMetadata();
- boolean intentCanBubble = metadata != null
- && canLaunchInActivityView(getContext(), metadata.getIntent(), pkg);
+ if (!canBubble(r, pkg, userId)) {
+ // no log: canBubble has its own
+ return false;
+ }
- // Does the app want to bubble & is able to bubble
- boolean canBubble = intentCanBubble
- && mPreferencesHelper.areBubblesAllowed(pkg, userId)
- && mPreferencesHelper.bubblesEnabled(r.sbn.getUser())
- && r.getChannel().canBubble()
- && !mActivityManager.isLowRamDevice();
+ if (mActivityManager.isLowRamDevice()) {
+ logBubbleError(r.getKey(), "low ram device");
+ return false;
+ }
- // Is the app in the foreground?
- final boolean appIsForeground =
- mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
+ if (mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND) {
+ // If the app is foreground it always gets to bubble
+ return true;
+ }
+
+ if (oldRecord != null && (oldRecord.getNotification().flags & FLAG_BUBBLE) != 0) {
+ // This is an update to an active bubble
+ return true;
+ }
- // Is the notification something we'd allow to bubble?
- // A call with a foreground service + person
+ // At this point the bubble must fulfill communication policy
+
+ // Communication always needs a person
ArrayList<Person> peopleList = notification.extras != null
? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)
: null;
- boolean isForegroundCall = CATEGORY_CALL.equals(notification.category)
- && (notification.flags & FLAG_FOREGROUND_SERVICE) != 0;
- // OR message style (which always has a person) with any remote input
- Class<? extends Notification.Style> style = notification.getNotificationStyle();
- boolean isMessageStyle = Notification.MessagingStyle.class.equals(style);
- boolean notificationAppropriateToBubble =
- (isMessageStyle && hasValidRemoteInput(notification))
- || (peopleList != null && !peopleList.isEmpty() && isForegroundCall);
+ // Message style requires a person & it's not included in the list
+ boolean isMessageStyle = Notification.MessagingStyle.class.equals(
+ notification.getNotificationStyle());
+ if (!isMessageStyle && (peopleList == null || peopleList.isEmpty())) {
+ logBubbleError(r.getKey(), "if not foreground, must have a person and be "
+ + "Notification.MessageStyle or Notification.CATEGORY_CALL");
+ return false;
+ }
+
+ // Communication is a message or a call
+ boolean isCall = CATEGORY_CALL.equals(notification.category);
+ boolean hasForegroundService = (notification.flags & FLAG_FOREGROUND_SERVICE) != 0;
+ if (isMessageStyle) {
+ if (hasValidRemoteInput(notification)) {
+ return true;
+ }
+ logBubbleError(r.getKey(), "messages require valid remote input");
+ return false;
+ } else if (isCall) {
+ if (hasForegroundService) {
+ return true;
+ }
+ logBubbleError(r.getKey(), "calls require foreground service");
+ return false;
+ }
+ logBubbleError(r.getKey(), "if not foreground, must be "
+ + "Notification.MessageStyle or Notification.CATEGORY_CALL");
+ return false;
+ }
- // OR something that was previously a bubble & still exists
- boolean bubbleUpdate = oldRecord != null
- && (oldRecord.getNotification().flags & FLAG_BUBBLE) != 0;
- return canBubble && (notificationAppropriateToBubble || appIsForeground || bubbleUpdate);
+ /**
+ * @return whether the user has enabled the provided notification to bubble, does not account
+ * for policy.
+ */
+ private boolean canBubble(NotificationRecord r, String pkg, int userId) {
+ Notification notification = r.getNotification();
+ Notification.BubbleMetadata metadata = notification.getBubbleMetadata();
+ if (metadata == null) {
+ // no log: no need to inform dev if they didn't attach bubble metadata
+ return false;
+ }
+ if (!canLaunchInActivityView(getContext(), metadata.getIntent(), pkg)) {
+ // no log: method has the failure log
+ return false;
+ }
+ if (!mPreferencesHelper.bubblesEnabled()) {
+ logBubbleError(r.getKey(), "bubbles disabled for user: " + userId);
+ return false;
+ }
+ if (!mPreferencesHelper.areBubblesAllowed(pkg, userId)) {
+ logBubbleError(r.getKey(),
+ "bubbles for package: " + pkg + " disabled for user: " + userId);
+ return false;
+ }
+ if (!r.getChannel().canBubble()) {
+ logBubbleError(r.getKey(),
+ "bubbles for channel " + r.getChannel().getId() + " disabled");
+ return false;
+ }
+ return true;
}
private boolean hasValidRemoteInput(Notification n) {
@@ -4889,6 +5007,11 @@ public class NotificationManagerService extends SystemService {
return false;
}
+ private void logBubbleError(String key, String failureMessage) {
+ if (DBG) {
+ Log.w(TAG, "Bubble notification: " + key + " failed: " + failureMessage);
+ }
+ }
/**
* Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
*
@@ -5251,12 +5374,26 @@ public class NotificationManagerService extends SystemService {
return;
}
+ // Bubbled children get to stick around if the summary was manually cancelled
+ // (user removed) from systemui.
+ FlagChecker childrenFlagChecker = null;
+ if (mReason == REASON_CANCEL
+ || mReason == REASON_CLICK
+ || mReason == REASON_CANCEL_ALL) {
+ childrenFlagChecker = (flags) -> {
+ if ((flags & FLAG_BUBBLE) != 0) {
+ return false;
+ }
+ return true;
+ };
+ }
+
// Cancel the notification.
boolean wasPosted = removeFromNotificationListsLocked(r);
cancelNotificationLocked(
r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName);
cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName,
- mSendDelete, null);
+ mSendDelete, childrenFlagChecker);
updateLightsLocked();
} else {
// No notification was found, assume that it is snoozed and cancel it.
@@ -5339,11 +5476,18 @@ public class NotificationManagerService extends SystemService {
}
@GuardedBy("mNotificationLock")
- private boolean isPackageSuspendedLocked(NotificationRecord r) {
- final String pkg = r.sbn.getPackageName();
- final int callingUid = r.sbn.getUid();
+ boolean isPackagePausedOrSuspended(String pkg, int uid) {
+ boolean isPaused;
+
+ final PackageManagerInternal pmi = LocalServices.getService(
+ PackageManagerInternal.class);
+ int flags = pmi.getDistractingPackageRestrictions(
+ pkg, Binder.getCallingUserHandle().getIdentifier());
+ isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0);
+
+ isPaused |= isPackageSuspendedForUser(pkg, uid);
- return isPackageSuspendedForUser(pkg, callingUid);
+ return isPaused;
}
protected class PostNotificationRunnable implements Runnable {
@@ -5376,7 +5520,8 @@ public class NotificationManagerService extends SystemService {
return;
}
- final boolean isPackageSuspended = isPackageSuspendedLocked(r);
+ final boolean isPackageSuspended =
+ isPackagePausedOrSuspended(r.sbn.getPackageName(), r.getUid());
r.setHidden(isPackageSuspended);
if (isPackageSuspended) {
mUsageStats.registerSuspendedByAdmin(r);
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 7b45a1b1997c..4835c97f0bb7 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -73,6 +73,9 @@ public class PreferencesHelper implements RankingConfig {
private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":";
@VisibleForTesting
+ static final int NOTIFICATION_CHANNEL_COUNT_LIMIT = 50000;
+
+ @VisibleForTesting
static final String TAG_RANKING = "ranking";
private static final String TAG_PACKAGE = "package";
private static final String TAG_CHANNEL = "channel";
@@ -100,7 +103,7 @@ public class PreferencesHelper implements RankingConfig {
@VisibleForTesting
static final boolean DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS = false;
private static final boolean DEFAULT_SHOW_BADGE = true;
- private static final boolean DEFAULT_ALLOW_BUBBLE = true;
+ static final boolean DEFAULT_ALLOW_BUBBLE = true;
private static final boolean DEFAULT_OEM_LOCKED_IMPORTANCE = false;
private static final boolean DEFAULT_APP_LOCKED_IMPORTANCE = false;
@@ -130,7 +133,7 @@ public class PreferencesHelper implements RankingConfig {
private final ZenModeHelper mZenModeHelper;
private SparseBooleanArray mBadgingEnabled;
- private SparseBooleanArray mBubblesEnabled;
+ private boolean mBubblesEnabled = DEFAULT_ALLOW_BUBBLE;
private boolean mAreChannelsBypassingDnd;
private boolean mHideSilentStatusBarIcons = DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS;
@@ -179,6 +182,7 @@ public class PreferencesHelper implements RankingConfig {
// noop
}
}
+ boolean skipWarningLogged = false;
PackagePreferences r = getOrCreatePackagePreferencesLocked(name, uid,
XmlUtils.readIntAttribute(
@@ -225,6 +229,14 @@ public class PreferencesHelper implements RankingConfig {
}
// Channels
if (TAG_CHANNEL.equals(tagName)) {
+ if (r.channels.size() >= NOTIFICATION_CHANNEL_COUNT_LIMIT) {
+ if (!skipWarningLogged) {
+ Slog.w(TAG, "Skipping further channels for " + r.pkg
+ + "; app has too many");
+ skipWarningLogged = true;
+ }
+ continue;
+ }
String id = parser.getAttributeValue(null, ATT_ID);
String channelName = parser.getAttributeValue(null, ATT_NAME);
int channelImportance = XmlUtils.readIntAttribute(
@@ -690,6 +702,10 @@ public class PreferencesHelper implements RankingConfig {
return needsPolicyFileChange;
}
+ if (r.channels.size() >= NOTIFICATION_CHANNEL_COUNT_LIMIT) {
+ throw new IllegalStateException("Limit exceed; cannot create more channels");
+ }
+
needsPolicyFileChange = true;
if (channel.getImportance() < IMPORTANCE_NONE
@@ -1818,40 +1834,19 @@ public class PreferencesHelper implements RankingConfig {
}
public void updateBubblesEnabled() {
- if (mBubblesEnabled == null) {
- mBubblesEnabled = new SparseBooleanArray();
- }
- boolean changed = false;
- // update the cached values
- for (int index = 0; index < mBubblesEnabled.size(); index++) {
- int userId = mBubblesEnabled.keyAt(index);
- final boolean oldValue = mBubblesEnabled.get(userId);
- final boolean newValue = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.NOTIFICATION_BUBBLES,
- DEFAULT_ALLOW_BUBBLE ? 1 : 0, userId) != 0;
- mBubblesEnabled.put(userId, newValue);
- changed |= oldValue != newValue;
- }
- if (changed) {
+ final boolean newValue = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.NOTIFICATION_BUBBLES,
+ DEFAULT_ALLOW_BUBBLE ? 1 : 0) == 1;
+ if (newValue != mBubblesEnabled) {
+ mBubblesEnabled = newValue;
updateConfig();
}
}
- public boolean bubblesEnabled(UserHandle userHandle) {
- int userId = userHandle.getIdentifier();
- if (userId == UserHandle.USER_ALL) {
- return false;
- }
- if (mBubblesEnabled.indexOfKey(userId) < 0) {
- mBubblesEnabled.put(userId,
- Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.NOTIFICATION_BUBBLES,
- DEFAULT_ALLOW_BUBBLE ? 1 : 0, userId) != 0);
- }
- return mBubblesEnabled.get(userId, DEFAULT_ALLOW_BUBBLE);
+ public boolean bubblesEnabled() {
+ return mBubblesEnabled;
}
-
public void updateBadgingEnabled() {
if (mBadgingEnabled == null) {
mBadgingEnabled = new SparseBooleanArray();
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 5de00e43a05d..7816f3619023 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -30,7 +30,7 @@ public interface RankingConfig {
boolean canShowBadge(String packageName, int uid);
boolean badgingEnabled(UserHandle userHandle);
boolean areBubblesAllowed(String packageName, int uid);
- boolean bubblesEnabled(UserHandle userHandle);
+ boolean bubblesEnabled();
boolean isGroupBlocked(String packageName, int uid, String groupId);
Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index c6af7566a8bd..8f05636eed9c 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -179,6 +179,7 @@ public class ZenLog {
case TYPE_SUPPRESSOR_CHANGED: return "suppressor_changed";
case TYPE_LISTENER_HINTS_CHANGED: return "listener_hints_changed";
case TYPE_SET_NOTIFICATION_POLICY: return "set_notification_policy";
+ case TYPE_SET_CONSOLIDATED_ZEN_POLICY: return "set_consolidated_policy";
default: return "unknown";
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index f81015dae468..ebc41916d034 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -942,12 +942,11 @@ public class ZenModeHelper {
}
private void applyCustomPolicy(ZenPolicy policy, ZenRule rule) {
- if (rule.zenMode == NotificationManager.INTERRUPTION_FILTER_NONE) {
+ if (rule.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
policy.apply(new ZenPolicy.Builder()
.disallowAllSounds()
.build());
- } else if (rule.zenMode
- == NotificationManager.INTERRUPTION_FILTER_ALARMS) {
+ } else if (rule.zenMode == Global.ZEN_MODE_ALARMS) {
policy.apply(new ZenPolicy.Builder()
.disallowAllSounds()
.allowAlarms(true)
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index da69986cd59f..965ddc9f2782 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -751,7 +751,7 @@ public final class OverlayManagerService extends SystemService {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
final DumpState dumpState = new DumpState();
- dumpState.setUserId(UserHandle.getUserId(Binder.getCallingUid()));
+ dumpState.setUserId(UserHandle.USER_ALL);
int opti = 0;
while (opti < args.length) {
@@ -771,13 +771,13 @@ public final class OverlayManagerService extends SystemService {
pw.println(" so the following are equivalent: mState, mstate, State, state.");
return;
} else if ("--user".equals(opt)) {
- opti++;
if (opti >= args.length) {
pw.println("Error: user missing argument");
return;
}
try {
dumpState.setUserId(Integer.parseInt(args[opti]));
+ opti++;
} catch (NumberFormatException e) {
pw.println("Error: user argument is not a number: " + args[opti]);
return;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 0032e9a8ea51..e75f545eafaa 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -505,6 +505,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
params.installFlags &= ~PackageManager.INSTALL_REQUEST_DOWNGRADE;
}
+ if (callingUid != Process.SYSTEM_UID) {
+ // Only system_server can use INSTALL_DISABLE_VERIFICATION.
+ params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION;
+ }
+
boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0;
if (params.isStaged || isApex) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d7d73451e74b..f36d512e38e3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -198,6 +198,7 @@ import android.content.pm.VersionedPackage;
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.IArtManager;
+import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.content.res.Resources;
import android.content.rollback.IRollbackManager;
import android.database.ContentObserver;
@@ -238,6 +239,7 @@ import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
+import android.permission.PermissionManager;
import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings.Global;
@@ -2024,6 +2026,14 @@ public class PackageManagerService extends IPackageManager.Stub
pkgList.add(packageName);
sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
}
+ } else if (!ArrayUtils.isEmpty(res.libraryConsumers)) { // if static shared lib
+ for (int i = 0; i < res.libraryConsumers.size(); i++) {
+ PackageParser.Package pkg = res.libraryConsumers.get(i);
+ // send broadcast that all consumers of the static shared library have changed
+ sendPackageChangedBroadcast(pkg.packageName, false /*killFlag*/,
+ new ArrayList<>(Collections.singletonList(pkg.packageName)),
+ pkg.applicationInfo.uid);
+ }
}
// Work that needs to happen on first install within each user
@@ -2122,6 +2132,12 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ @Override
+ public List<SplitPermissionInfoParcelable> getSplitPermissions() {
+ return PermissionManager.splitPermissionInfoListToParcelableList(
+ SystemConfig.getInstance().getSplitPermissions());
+ }
+
private void notifyInstallObserver(String packageName) {
Pair<PackageInstalledInfo, IPackageInstallObserver2> pair =
mNoKillInstallObservers.remove(packageName);
@@ -12207,6 +12223,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
}
+ if (reconciledPkg.installResult != null) {
+ reconciledPkg.installResult.libraryConsumers = clientLibPkgs;
+ }
if ((scanFlags & SCAN_BOOTING) != 0) {
// No apps can run during boot scan, so they don't need to be frozen
@@ -16060,6 +16079,8 @@ public class PackageManagerService extends IPackageManager.Stub
String installerPackageName;
PackageRemovedInfo removedInfo;
ArrayMap<String, PackageInstalledInfo> addedChildPackages;
+ // The set of packages consuming this shared library or null if no consumers exist.
+ ArrayList<PackageParser.Package> libraryConsumers;
public void setError(int code, String msg) {
setReturnCode(code);
@@ -18814,8 +18835,14 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
if (removedAppId >= 0) {
+ // If a system app's updates are uninstalled the UID is not actually removed. Some
+ // services need to know the package name affected.
+ if (extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
+ extras.putString(Intent.EXTRA_PACKAGE_NAME, removedPackage);
+ }
+
packageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED,
- null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
+ null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
null, null, broadcastUsers, instantUserIds);
}
}
@@ -18904,19 +18931,20 @@ public class PackageManagerService extends IPackageManager.Stub
// or packages running under the shared user of the removed
// package if revoking the permissions requested only by the removed
// package is successful and this causes a change in gids.
+ boolean shouldKill = false;
for (int userId : UserManagerService.getInstance().getUserIds()) {
final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs,
userId);
- if (userIdToKill == UserHandle.USER_ALL
- || userIdToKill >= UserHandle.USER_SYSTEM) {
- // If gids changed for this user, kill all affected packages.
- mHandler.post(() -> {
- // This has to happen with no lock held.
- killApplication(deletedPs.name, deletedPs.appId,
- KILL_APP_REASON_GIDS_CHANGED);
- });
- break;
- }
+ shouldKill |= userIdToKill == UserHandle.USER_ALL
+ || userIdToKill >= UserHandle.USER_SYSTEM;
+ }
+ // If gids changed, kill all affected packages.
+ if (shouldKill) {
+ mHandler.post(() -> {
+ // This has to happen with no lock held.
+ killApplication(deletedPs.name, deletedPs.appId,
+ KILL_APP_REASON_GIDS_CHANGED);
+ });
}
}
clearPackagePreferredActivitiesLPw(
@@ -20873,7 +20901,7 @@ public class PackageManagerService extends IPackageManager.Stub
public void sendSessionCommitBroadcast(PackageInstaller.SessionInfo sessionInfo, int userId) {
UserManagerService ums = UserManagerService.getInstance();
- if (ums != null) {
+ if (ums != null && !sessionInfo.isStaged()) {
final UserInfo parent = ums.getProfileParent(userId);
final int launcherUid = (parent != null) ? parent.id : userId;
final ComponentName launcherComponent = getDefaultHomeActivity(launcherUid);
diff --git a/services/core/java/com/android/server/pm/ProtectedPackages.java b/services/core/java/com/android/server/pm/ProtectedPackages.java
index a374e1484b28..231168e9c660 100644
--- a/services/core/java/com/android/server/pm/ProtectedPackages.java
+++ b/services/core/java/com/android/server/pm/ProtectedPackages.java
@@ -92,6 +92,9 @@ public class ProtectedPackages {
if (mDeviceOwnerUserId == userId) {
return mDeviceOwnerPackage;
}
+ if (mProfileOwnerPackages == null) {
+ return null;
+ }
return mProfileOwnerPackages.get(userId);
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 5870986a264f..2eedf0c696e2 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -190,6 +190,7 @@ public final class DefaultPermissionGrantPolicy {
static {
STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE);
STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+ STORAGE_PERMISSIONS.add(Manifest.permission.ACCESS_MEDIA_LOCATION);
}
private static final int MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS = 1;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 6a7c622b7e33..6fced8acf1df 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -967,10 +967,12 @@ public class PermissionManagerService {
// or has updated its target SDK and AR is no longer implicit to it.
// This is a compatibility workaround for apps when AR permission was
// split in Q.
- int numSplitPerms = PermissionManager.SPLIT_PERMISSIONS.size();
+ final List<PermissionManager.SplitPermissionInfo> permissionList =
+ getSplitPermissions();
+ int numSplitPerms = permissionList.size();
for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
PermissionManager.SplitPermissionInfo sp =
- PermissionManager.SPLIT_PERMISSIONS.get(splitPermNum);
+ permissionList.get(splitPermNum);
String splitPermName = sp.getSplitPermission();
if (sp.getNewPermissions().contains(permName)
&& origPermissions.hasInstallPermission(splitPermName)) {
@@ -1537,10 +1539,10 @@ public class PermissionManagerService {
String pkgName = pkg.packageName;
ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>();
- int numSplitPerms = PermissionManager.SPLIT_PERMISSIONS.size();
+ final List<PermissionManager.SplitPermissionInfo> permissionList = getSplitPermissions();
+ int numSplitPerms = permissionList.size();
for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
- PermissionManager.SplitPermissionInfo spi =
- PermissionManager.SPLIT_PERMISSIONS.get(splitPermNum);
+ PermissionManager.SplitPermissionInfo spi = permissionList.get(splitPermNum);
List<String> newPerms = spi.getNewPermissions();
int numNewPerms = newPerms.size();
@@ -1595,8 +1597,6 @@ public class PermissionManagerService {
Slog.i(TAG, newPerm + " does not inherit from " + sourcePerms
+ " for " + pkgName + " as split permission is also new");
}
-
- break;
} else {
// Inherit from new install or existing runtime permissions
inheritPermissionStateToNewImplicitPermissionLocked(sourcePerms,
@@ -1610,6 +1610,10 @@ public class PermissionManagerService {
return updatedUserIds;
}
+ private List<PermissionManager.SplitPermissionInfo> getSplitPermissions() {
+ return SystemConfig.getInstance().getSplitPermissions();
+ }
+
private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) {
boolean allowed = false;
final int NP = PackageParser.NEW_PERMISSIONS.length;
@@ -2035,16 +2039,6 @@ public class PermissionManagerService {
return whitelistedPermissions;
}
- private void setWhitelistedRestrictedPermissions(@NonNull PackageParser.Package pkg,
- @NonNull int[] userIds, @Nullable List<String> permissions, int callingUid,
- @PackageManager.PermissionWhitelistFlags int whitelistFlags,
- @NonNull PermissionCallback callback) {
- for (int userId : userIds) {
- setWhitelistedRestrictedPermissionsForUser(pkg, userId, permissions,
- callingUid, whitelistFlags, callback);
- }
- }
-
private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId,
String[] grantedPermissions, int callingUid, PermissionCallback callback) {
PackageSetting ps = (PackageSetting) pkg.mExtras;
@@ -2325,109 +2319,122 @@ public class PermissionManagerService {
}
}
- private void setWhitelistedRestrictedPermissionsForUser(@NonNull PackageParser.Package pkg,
- @UserIdInt int userId, @Nullable List<String> permissions, int callingUid,
- @PermissionWhitelistFlags int whitelistFlags, PermissionCallback callback) {
+ private void setWhitelistedRestrictedPermissions(@NonNull PackageParser.Package pkg,
+ @NonNull int[] userIds, @Nullable List<String> permissions, int callingUid,
+ @PackageManager.PermissionWhitelistFlags int whitelistFlags,
+ @NonNull PermissionCallback callback) {
+
final PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps == null) {
return;
}
final PermissionsState permissionsState = ps.getPermissionsState();
-
- ArraySet<String> oldGrantedRestrictedPermissions = null;
+ SparseArray<ArraySet<String>> oldGrantedRestrictedPermissionsByUser = new SparseArray<>();
boolean updatePermissions = false;
final int permissionCount = pkg.requestedPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- final String permissionName = pkg.requestedPermissions.get(i);
-
- final BasePermission bp = mSettings.getPermissionLocked(permissionName);
- if (bp == null) {
- Slog.w(TAG, "Cannot whitelist unknown permission: " + permissionName);
- continue;
- }
+ for (int userId : userIds) {
+ for (int i = 0; i < permissionCount; i++) {
+ final String permissionName = pkg.requestedPermissions.get(i);
- if (!bp.isHardOrSoftRestricted()) {
- continue;
- }
+ final BasePermission bp = mSettings.getPermissionLocked(permissionName);
+ if (bp == null) {
+ Slog.w(TAG, "Cannot whitelist unknown permission: " + permissionName);
+ continue;
+ }
- if (permissionsState.hasPermission(permissionName, userId)) {
- if (oldGrantedRestrictedPermissions == null) {
- oldGrantedRestrictedPermissions = new ArraySet<>();
+ if (!bp.isHardOrSoftRestricted()) {
+ continue;
}
- oldGrantedRestrictedPermissions.add(permissionName);
- }
- final int oldFlags = permissionsState.getPermissionFlags(permissionName, userId);
+ if (permissionsState.hasPermission(permissionName, userId)) {
+ if (oldGrantedRestrictedPermissionsByUser.get(userId) == null) {
+ oldGrantedRestrictedPermissionsByUser.put(userId, new ArraySet<>());
+ }
+ oldGrantedRestrictedPermissionsByUser.get(userId).add(permissionName);
+ }
- int newFlags = oldFlags;
- int mask = 0;
- int whitelistFlagsCopy = whitelistFlags;
- while (whitelistFlagsCopy != 0) {
- final int flag = 1 << Integer.numberOfTrailingZeros(whitelistFlagsCopy);
- whitelistFlagsCopy &= ~flag;
- switch (flag) {
- case FLAG_PERMISSION_WHITELIST_SYSTEM: {
- mask |= PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
- if (permissions != null && permissions.contains(permissionName)) {
- newFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
- } else {
- newFlags &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+ final int oldFlags = permissionsState.getPermissionFlags(permissionName, userId);
+
+ int newFlags = oldFlags;
+ int mask = 0;
+ int whitelistFlagsCopy = whitelistFlags;
+ while (whitelistFlagsCopy != 0) {
+ final int flag = 1 << Integer.numberOfTrailingZeros(whitelistFlagsCopy);
+ whitelistFlagsCopy &= ~flag;
+ switch (flag) {
+ case FLAG_PERMISSION_WHITELIST_SYSTEM: {
+ mask |= PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+ if (permissions != null && permissions.contains(permissionName)) {
+ newFlags |=
+ PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+ } else {
+ newFlags &=
+ ~PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+ }
}
- } break;
- case FLAG_PERMISSION_WHITELIST_UPGRADE: {
- mask |= PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
- if (permissions != null && permissions.contains(permissionName)) {
- newFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
- } else {
- newFlags &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+ break;
+ case FLAG_PERMISSION_WHITELIST_UPGRADE: {
+ mask |= PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+ if (permissions != null && permissions.contains(permissionName)) {
+ newFlags |=
+ PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+ } else {
+ newFlags &=
+ ~PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+ }
}
- } break;
- case FLAG_PERMISSION_WHITELIST_INSTALLER: {
- mask |= PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
- if (permissions != null && permissions.contains(permissionName)) {
- newFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
- } else {
- newFlags &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+ break;
+ case FLAG_PERMISSION_WHITELIST_INSTALLER: {
+ mask |= PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+ if (permissions != null && permissions.contains(permissionName)) {
+ newFlags |=
+ PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+ } else {
+ newFlags &= ~PackageManager
+ .FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+ }
}
- } break;
+ break;
+ }
}
- }
-
- if (oldFlags == newFlags) {
- continue;
- }
- updatePermissions = true;
+ if (oldFlags == newFlags) {
+ continue;
+ }
- final boolean wasWhitelisted = (oldFlags
- & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
- final boolean isWhitelisted = (newFlags
- & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
+ updatePermissions = true;
+
+ final boolean wasWhitelisted = (oldFlags
+ & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
+ final boolean isWhitelisted = (newFlags
+ & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
+
+ // If the permission is policy fixed as granted but it is no longer
+ // on any of the whitelists we need to clear the policy fixed flag
+ // as whitelisting trumps policy i.e. policy cannot grant a non
+ // grantable permission.
+ if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
+ final boolean isGranted = permissionsState.hasPermission(permissionName,
+ userId);
+ if (!isWhitelisted && isGranted) {
+ mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+ newFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+ }
+ }
- // If the permission is policy fixed as granted but it is no longer
- // on any of the whitelists we need to clear the policy fixed flag
- // as whitelisting trumps policy i.e. policy cannot grant a non
- // grantable permission.
- if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
- final boolean isGranted = permissionsState.hasPermission(permissionName, userId);
- if (!isWhitelisted && isGranted) {
- mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
- newFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+ // If we are whitelisting an app that does not support runtime permissions
+ // we need to make sure it goes through the permission review UI at launch.
+ if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+ && !wasWhitelisted && isWhitelisted) {
+ mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+ newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
}
- }
- // If we are whitelisting an app that does not support runtime permissions
- // we need to make sure it goes through the permission review UI at launch.
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
- && !wasWhitelisted && isWhitelisted) {
- mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
- newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+ updatePermissionFlags(permissionName, pkg.packageName, mask, newFlags,
+ callingUid, userId, false, null /*callback*/);
}
-
- updatePermissionFlags(permissionName, pkg.packageName, mask, newFlags,
- callingUid, userId, false, null /*callback*/);
}
if (updatePermissions) {
@@ -2435,7 +2442,12 @@ public class PermissionManagerService {
restorePermissionState(pkg, false, pkg.packageName, callback);
// If this resulted in losing a permission we need to kill the app.
- if (oldGrantedRestrictedPermissions != null) {
+ int oldGrantedRestrictedPermissionsByUserCount =
+ oldGrantedRestrictedPermissionsByUser.size();
+ for (int j = 0; j < oldGrantedRestrictedPermissionsByUserCount; j++) {
+ final int userId = oldGrantedRestrictedPermissionsByUser.keyAt(j);
+ final ArraySet<String> oldGrantedRestrictedPermissions =
+ oldGrantedRestrictedPermissionsByUser.valueAt(j);
final int oldGrantedCount = oldGrantedRestrictedPermissions.size();
for (int i = 0; i < oldGrantedCount; i++) {
final String permission = oldGrantedRestrictedPermissions.valueAt(i);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 21b13fe234e0..48056b47e1bd 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -107,6 +107,7 @@ import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
import android.app.IUiModeManager;
+import android.app.NotificationManager;
import android.app.ProgressDialog;
import android.app.SearchManager;
import android.app.UiModeManager;
@@ -2572,6 +2573,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
}
+ NotificationManager getNotificationService() {
+ return mContext.getSystemService(NotificationManager.class);
+ }
+
static IAudioService getAudioService() {
IAudioService audioService = IAudioService.Stub.asInterface(
ServiceManager.checkService(Context.AUDIO_SERVICE));
@@ -3806,6 +3811,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (down) {
sendSystemKeyToStatusBarAsync(event.getKeyCode());
+ NotificationManager nm = getNotificationService();
+ if (nm != null && !mHandleVolumeKeysInWM) {
+ nm.silenceNotificationSound();
+ }
+
TelecomManager telecomManager = getTelecommService();
if (telecomManager != null && !mHandleVolumeKeysInWM) {
// When {@link #mHandleVolumeKeysInWM} is set, volume key events
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
index 77bf930fb4d7..712012d9e621 100644
--- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
+++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
@@ -24,20 +24,17 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
-import android.os.Debug;
import android.provider.Settings;
-import android.telecom.TelecomManager;
import android.text.TextUtils;
-import android.util.Log;
import android.util.Slog;
+import com.android.internal.R;
import com.android.internal.telephony.SmsApplication;
import com.android.internal.util.CollectionUtils;
import com.android.server.LocalServices;
import com.android.server.role.RoleManagerService;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -67,14 +64,25 @@ public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHolder
public List<String> getRoleHolders(@NonNull String roleName, @UserIdInt int userId) {
switch (roleName) {
case RoleManager.ROLE_ASSISTANT: {
- String legacyAssistant = Settings.Secure.getStringForUser(
- mContext.getContentResolver(), Settings.Secure.ASSISTANT, userId);
- if (legacyAssistant == null || legacyAssistant.isEmpty()) {
- return Collections.emptyList();
+ String packageName;
+ String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ Settings.Secure.ASSISTANT, userId);
+ // AssistUtils was using the default assistant app if Settings.Secure.ASSISTANT is
+ // null, while only an empty string means user selected "None".
+ if (setting != null) {
+ if (!setting.isEmpty()) {
+ ComponentName componentName = ComponentName.unflattenFromString(setting);
+ packageName = componentName != null ? componentName.getPackageName() : null;
+ } else {
+ packageName = null;
+ }
+ } else if (mContext.getPackageManager().isDeviceUpgrading()) {
+ String defaultAssistant = mContext.getString(R.string.config_defaultAssistant);
+ packageName = !TextUtils.isEmpty(defaultAssistant) ? defaultAssistant : null;
} else {
- return Collections.singletonList(
- ComponentName.unflattenFromString(legacyAssistant).getPackageName());
+ packageName = null;
}
+ return CollectionUtils.singletonOrEmpty(packageName);
}
case RoleManager.ROLE_BROWSER: {
PackageManagerInternal packageManagerInternal = LocalServices.getService(
@@ -84,44 +92,36 @@ public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHolder
return CollectionUtils.singletonOrEmpty(packageName);
}
case RoleManager.ROLE_DIALER: {
- String setting = Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
+ String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
Settings.Secure.DIALER_DEFAULT_APPLICATION, userId);
- return CollectionUtils.singletonOrEmpty(!TextUtils.isEmpty(setting)
- ? setting
- : mContext.getSystemService(TelecomManager.class).getSystemDialerPackage());
+ String packageName;
+ if (!TextUtils.isEmpty(setting)) {
+ packageName = setting;
+ } else if (mContext.getPackageManager().isDeviceUpgrading()) {
+ // DefaultDialerManager was using the default dialer app if
+ // Settings.Secure.DIALER_DEFAULT_APPLICATION is invalid.
+ // TelecomManager.getSystemDialerPackage() won't work because it might not
+ // be ready.
+ packageName = mContext.getString(R.string.config_defaultDialer);
+ } else {
+ packageName = null;
+ }
+ return CollectionUtils.singletonOrEmpty(packageName);
}
case RoleManager.ROLE_SMS: {
- // Moved over from SmsApplication#getApplication
- String result = Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
+ String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
- // TODO: STOPSHIP: Remove the following code once we read the value of
- // config_defaultSms in RoleControllerService.
- if (result == null) {
- Collection<SmsApplication.SmsApplicationData> applications =
- SmsApplication.getApplicationCollectionAsUser(mContext, userId);
- SmsApplication.SmsApplicationData applicationData;
- String defaultPackage = mContext.getResources()
- .getString(com.android.internal.R.string.default_sms_application);
- applicationData =
- SmsApplication.getApplicationForPackage(applications, defaultPackage);
-
- if (applicationData == null) {
- // Are there any applications?
- if (applications.size() != 0) {
- applicationData =
- (SmsApplication.SmsApplicationData) applications.toArray()[0];
- }
- }
- if (DEBUG) {
- Log.i(LOG_TAG, "Found default sms app: " + applicationData
- + " among: " + applications + " from " + Debug.getCallers(4));
- }
- SmsApplication.SmsApplicationData app = applicationData;
- result = app == null ? null : app.mPackageName;
+ String packageName;
+ if (!TextUtils.isEmpty(setting)) {
+ packageName = setting;
+ } else if (mContext.getPackageManager().isDeviceUpgrading()) {
+ // SmsApplication was using the default SMS app if
+ // Settings.Secure.DIALER_DEFAULT_APPLICATION is invalid.
+ packageName = mContext.getString(R.string.config_defaultSms);
+ } else {
+ packageName = null;
}
- return CollectionUtils.singletonOrEmpty(result);
+ return CollectionUtils.singletonOrEmpty(packageName);
}
case RoleManager.ROLE_HOME: {
PackageManager packageManager = mContext.getPackageManager();
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index aa49ba62f48b..e1b3e4d6fbcf 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -542,6 +542,10 @@ public final class PowerManagerService extends SystemService
// True if we in the process of performing a forceSuspend
private boolean mForceSuspendActive;
+ // Transition to Doze is in progress. We have transitioned to WAKEFULNESS_DOZING,
+ // but the DreamService has not yet been told to start (it's an async process).
+ private boolean mDozeStartInProgress;
+
private final class ForegroundProfileObserver extends SynchronousUserSwitchObserver {
@Override
public void onUserSwitching(int newUserId) throws RemoteException {}
@@ -1514,6 +1518,7 @@ public final class PowerManagerService extends SystemService
mLastSleepTime = eventTime;
mLastSleepReason = reason;
mSandmanSummoned = true;
+ mDozeStartInProgress = true;
setWakefulnessLocked(WAKEFULNESS_DOZING, reason, eventTime);
// Report the number of wake locks that will be cleared by going to sleep.
@@ -1601,6 +1606,10 @@ public final class PowerManagerService extends SystemService
mWakefulness = wakefulness;
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
+
+ // This is only valid while we are in wakefulness dozing. Set to false otherwise.
+ mDozeStartInProgress &= (mWakefulness == WAKEFULNESS_DOZING);
+
if (mNotifier != null) {
mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
}
@@ -1631,6 +1640,9 @@ public final class PowerManagerService extends SystemService
if (mWakefulness == WAKEFULNESS_DOZING
&& (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {
return; // wait until dream has enabled dozing
+ } else {
+ // Doze wakelock acquired (doze started) or device is no longer dozing.
+ mDozeStartInProgress = false;
}
if (mWakefulness == WAKEFULNESS_DOZING || mWakefulness == WAKEFULNESS_ASLEEP) {
logSleepTimeoutRecapturedLocked();
@@ -2309,6 +2321,10 @@ public final class PowerManagerService extends SystemService
isDreaming = false;
}
+ // At this point, we either attempted to start the dream or no attempt will be made,
+ // so stop holding the display suspend blocker for Doze.
+ mDozeStartInProgress = false;
+
// Update dream state.
synchronized (mLock) {
// Remember the initial battery level when the dream started.
@@ -2735,6 +2751,16 @@ public final class PowerManagerService extends SystemService
if (mScreenBrightnessBoostInProgress) {
return true;
}
+
+ // When we transition to DOZING, we have to keep the display suspend blocker
+ // up until the Doze service has a change to acquire the DOZE wakelock.
+ // Here we wait for mWakefulnessChanging to become false since the wakefulness
+ // transition to DOZING isn't considered "changed" until the doze wake lock is
+ // acquired.
+ if (mWakefulness == WAKEFULNESS_DOZING && mDozeStartInProgress) {
+ return true;
+ }
+
// Let the system suspend if the screen is off or dozing.
return false;
}
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 1552fd517d30..491c5ab2ac03 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -38,11 +38,13 @@ import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.Temperature;
import android.util.ArrayMap;
+import android.util.EventLog;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
+import com.android.server.EventLogTags;
import com.android.server.FgThread;
import com.android.server.SystemService;
@@ -250,6 +252,8 @@ public class ThermalManagerService extends SystemService {
} finally {
mThermalEventListeners.finishBroadcast();
}
+ EventLog.writeEvent(EventLogTags.THERMAL_CHANGED, temperature.getName(),
+ temperature.getType(), temperature.getValue(), temperature.getStatus(), mStatus);
}
private void shutdownIfNeeded(Temperature temperature) {
@@ -860,10 +864,10 @@ public class ThermalManagerService extends SystemService {
mThermalHal11.linkToDeath(new DeathRecipient(),
THERMAL_HAL_DEATH_COOKIE);
mThermalHal11.registerThermalCallback(mThermalCallback11);
+ Slog.i(TAG, "Thermal HAL 1.1 service connected, limited thermal functions "
+ + "due to legacy API.");
} catch (NoSuchElementException | RemoteException e) {
- Slog.e(TAG,
- "Thermal HAL 1.1 service not connected, no thermal call back will be "
- + "called.");
+ Slog.e(TAG, "Thermal HAL 1.1 service not connected.");
mThermalHal11 = null;
}
return (mThermalHal11 != null);
@@ -978,8 +982,9 @@ public class ThermalManagerService extends SystemService {
mThermalHal20.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE);
mThermalHal20.registerThermalChangedCallback(mThermalCallback20, false,
0 /* not used */);
+ Slog.i(TAG, "Thermal HAL 2.0 service connected.");
} catch (NoSuchElementException | RemoteException e) {
- Slog.e(TAG, "Thermal HAL 2.0 service not connected, trying 1.1.");
+ Slog.e(TAG, "Thermal HAL 2.0 service not connected.");
mThermalHal20 = null;
}
return (mThermalHal20 != null);
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index e107c9aedf38..08c1bb536211 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -86,9 +86,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
private static final String TAG = "RollbackManager";
- // Rollbacks expire after 48 hours.
+ // Rollbacks expire after 14 days.
private static final long DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS =
- TimeUnit.HOURS.toMillis(48);
+ TimeUnit.DAYS.toMillis(14);
// Lock used to synchronize accesses to in-memory rollback data
// structures. By convention, methods with the suffix "Locked" require
@@ -1289,7 +1289,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
private boolean packageVersionsEqual(VersionedPackage a, VersionedPackage b) {
- return a.getPackageName().equals(b.getPackageName())
+ return a != null && b != null
+ && a.getPackageName().equals(b.getPackageName())
&& a.getLongVersionCode() == b.getLongVersionCode();
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 9908b3657121..b0f1e5d69be4 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1172,8 +1172,16 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
return false;
}
final int displayId = display.getDisplayId();
- return displayId == DEFAULT_DISPLAY
- || mWindowManagerInternal.shouldShowSystemDecorOnDisplay(displayId);
+ if (displayId == DEFAULT_DISPLAY) {
+ return true;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return mWindowManagerInternal.shouldShowSystemDecorOnDisplay(displayId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
void forEachDisplayConnector(Consumer<DisplayConnector> action) {
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdater.java b/services/core/java/com/android/server/webkit/WebViewUpdater.java
index a460040d0a60..3b58af2a200f 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdater.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdater.java
@@ -87,19 +87,6 @@ class WebViewUpdater {
newPackage = findPreferredWebViewPackage();
if (mCurrentWebViewPackage != null) {
oldProviderName = mCurrentWebViewPackage.packageName;
- if (changedState == WebViewUpdateService.PACKAGE_CHANGED
- && newPackage.packageName.equals(oldProviderName)) {
- // If we don't change package name we should only rerun the
- // preparation phase if the current package has been replaced
- // (not if it has been enabled/disabled).
- return;
- }
- if (newPackage.packageName.equals(oldProviderName)
- && (newPackage.lastUpdateTime
- == mCurrentWebViewPackage.lastUpdateTime)) {
- // If the chosen package hasn't been updated, then early-out
- return;
- }
}
// Only trigger update actions if the updated package is the one
// that will be used, or the one that was in use before the
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 4cfc1d1df2ae..afd6674edfa8 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -907,7 +907,7 @@ final class AccessibilityController {
}
public void releaseSurface() {
- mSurfaceControl.remove();
+ mService.mTransactionFactory.make().remove(mSurfaceControl).apply();
mSurface.release();
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index a18a53dfea92..242139cd2da7 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -5231,18 +5231,28 @@ class ActivityStack extends ConfigurationContainer {
* then skip running tasks that match those types.
*/
void getRunningTasks(List<TaskRecord> tasksOut, @ActivityType int ignoreActivityType,
- @WindowingMode int ignoreWindowingMode, int callingUid, boolean allowed) {
+ @WindowingMode int ignoreWindowingMode, int callingUid, boolean allowed,
+ boolean crossUser, ArraySet<Integer> profileIds) {
boolean focusedStack = mRootActivityContainer.getTopDisplayFocusedStack() == this;
boolean topTask = true;
+ int userId = UserHandle.getUserId(callingUid);
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
if (task.getTopActivity() == null) {
// Skip if there are no activities in the task
continue;
}
- if (!allowed && !task.isActivityTypeHome() && task.effectiveUid != callingUid) {
- // Skip if the caller can't fetch this task
- continue;
+ if (task.effectiveUid != callingUid) {
+ if (task.userId != userId && !crossUser && !profileIds.contains(task.userId)) {
+ // Skip if the caller does not have cross user permission or cannot access
+ // the task's profile
+ continue;
+ }
+ if (!allowed && !task.isActivityTypeHome()) {
+ // Skip if the caller isn't allowed to fetch this task, except for the home
+ // task which we always return.
+ continue;
+ }
}
if (ignoreActivityType != ACTIVITY_TYPE_UNDEFINED
&& task.getActivityType() == ignoreActivityType) {
@@ -5458,6 +5468,7 @@ class ActivityStack extends ConfigurationContainer {
task.cleanUpResourcesForDestroy();
}
+ final ActivityDisplay display = getDisplay();
if (mTaskHistory.isEmpty()) {
if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this);
// We only need to adjust focused stack if this stack is in focus and we are not in the
@@ -5466,11 +5477,11 @@ class ActivityStack extends ConfigurationContainer {
&& mRootActivityContainer.isTopDisplayFocusedStack(this)) {
String myReason = reason + " leftTaskHistoryEmpty";
if (!inMultiWindowMode() || adjustFocusToNextFocusableStack(myReason) == null) {
- getDisplay().moveHomeStackToFront(myReason);
+ display.moveHomeStackToFront(myReason);
}
}
if (isAttached()) {
- getDisplay().positionChildAtBottom(this);
+ display.positionChildAtBottom(this);
}
if (!isActivityTypeHome() || !isAttached()) {
remove();
@@ -5483,6 +5494,9 @@ class ActivityStack extends ConfigurationContainer {
if (inPinnedWindowingMode()) {
mService.getTaskChangeNotificationController().notifyActivityUnpinned();
}
+ if (display.isSingleTaskInstance()) {
+ mService.notifySingleTaskDisplayEmpty(display.mDisplayId);
+ }
}
TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 5a1eed8897b6..5b697ee89602 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2700,7 +2700,8 @@ class ActivityStarter {
|| mPreferredDisplayId != DEFAULT_DISPLAY) {
final boolean onTop = aOptions == null || !aOptions.getAvoidMoveToFront();
final ActivityStack stack =
- mRootActivityContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams);
+ mRootActivityContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams,
+ mRequest.realCallingPid, mRequest.realCallingUid);
return stack;
}
// Otherwise handle adjacent launch.
@@ -2818,11 +2819,24 @@ class ActivityStarter {
return this;
}
+ /**
+ * Sets the pid of the caller who originally started the activity.
+ *
+ * Normally, the pid/uid would be the calling pid from the binder call.
+ * However, in case of a {@link PendingIntent}, the pid/uid pair of the caller is considered
+ * the original entity that created the pending intent, in contrast to setRealCallingPid/Uid,
+ * which represents the entity who invoked pending intent via {@link PendingIntent#send}.
+ */
ActivityStarter setCallingPid(int pid) {
mRequest.callingPid = pid;
return this;
}
+ /**
+ * Sets the uid of the caller who originally started the activity.
+ *
+ * @see #setCallingPid
+ */
ActivityStarter setCallingUid(int uid) {
mRequest.callingUid = uid;
return this;
@@ -2833,11 +2847,25 @@ class ActivityStarter {
return this;
}
+ /**
+ * Sets the pid of the caller who requested to launch the activity.
+ *
+ * The pid/uid represents the caller who launches the activity in this request.
+ * It will almost same as setCallingPid/Uid except when processing {@link PendingIntent}:
+ * the pid/uid will be the caller who called {@link PendingIntent#send()}.
+ *
+ * @see #setCallingPid
+ */
ActivityStarter setRealCallingPid(int pid) {
mRequest.realCallingPid = pid;
return this;
}
+ /**
+ * Sets the uid of the caller who requested to launch the activity.
+ *
+ * @see #setRealCallingPid
+ */
ActivityStarter setRealCallingUid(int uid) {
mRequest.realCallingUid = uid;
return this;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 747837bc933f..223205377bb9 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -19,6 +19,8 @@ package com.android.server.wm;
import static android.Manifest.permission.BIND_VOICE_INTERACTION;
import static android.Manifest.permission.CHANGE_CONFIGURATION;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
@@ -213,6 +215,7 @@ import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.text.format.Time;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
@@ -2522,15 +2525,22 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@WindowConfiguration.ActivityType int ignoreActivityType,
@WindowConfiguration.WindowingMode int ignoreWindowingMode) {
final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final boolean crossUser = isCrossUserAllowed(callingPid, callingUid);
+ final int[] profileIds = getUserManager().getProfileIds(
+ UserHandle.getUserId(callingUid), true);
+ ArraySet<Integer> callingProfileIds = new ArraySet<>();
+ for (int i = 0; i < profileIds.length; i++) {
+ callingProfileIds.add(profileIds[i]);
+ }
ArrayList<ActivityManager.RunningTaskInfo> list = new ArrayList<>();
synchronized (mGlobalLock) {
if (DEBUG_ALL) Slog.v(TAG, "getTasks: max=" + maxNum);
- final boolean allowed = isGetTasksAllowed("getTasks", Binder.getCallingPid(),
- callingUid);
+ final boolean allowed = isGetTasksAllowed("getTasks", callingPid, callingUid);
mRootActivityContainer.getRunningTasks(maxNum, list, ignoreActivityType,
- ignoreWindowingMode, callingUid, allowed);
+ ignoreWindowingMode, callingUid, allowed, crossUser, callingProfileIds);
}
return list;
@@ -3587,6 +3597,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return allowed;
}
+ boolean isCrossUserAllowed(int pid, int uid) {
+ return checkPermission(INTERACT_ACROSS_USERS, pid, uid) == PERMISSION_GRANTED
+ || checkPermission(INTERACT_ACROSS_USERS_FULL, pid, uid) == PERMISSION_GRANTED;
+ }
+
private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
IAssistDataReceiver receiver, Bundle receiverExtras, IBinder activityToken,
boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout,
@@ -6048,6 +6063,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return allUids.contains(uid);
}
+ void notifySingleTaskDisplayEmpty(int displayId) {
+ mTaskChangeNotificationController.notifySingleTaskDisplayEmpty(displayId);
+ }
+
final class H extends Handler {
static final int REPORT_TIME_TRACKER_MSG = 1;
diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java
index 84ba5ca94f8c..7fc17e1e8462 100644
--- a/services/core/java/com/android/server/wm/BlackFrame.java
+++ b/services/core/java/com/android/server/wm/BlackFrame.java
@@ -97,6 +97,7 @@ public class BlackFrame {
final BlackSurface[] mBlackSurfaces = new BlackSurface[4];
final boolean mForceDefaultOrientation;
+ private final TransactionFactory mTransactionFactory;
public void printTo(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("Outer: "); mOuterRect.printShortString(pw);
@@ -111,11 +112,12 @@ public class BlackFrame {
}
}
- public BlackFrame(SurfaceControl.Transaction t,
- Rect outer, Rect inner, int layer, DisplayContent dc,
- boolean forceDefaultOrientation) throws OutOfResourcesException {
+ public BlackFrame(TransactionFactory factory, SurfaceControl.Transaction t, Rect outer,
+ Rect inner, int layer, DisplayContent dc, boolean forceDefaultOrientation)
+ throws OutOfResourcesException {
boolean success = false;
+ mTransactionFactory = factory;
mForceDefaultOrientation = forceDefaultOrientation;
// TODO: Why do we use 4 surfaces instead of just one big one behind the screenshot?
@@ -149,14 +151,16 @@ public class BlackFrame {
public void kill() {
if (mBlackSurfaces != null) {
+ SurfaceControl.Transaction t = mTransactionFactory.make();
for (int i=0; i<mBlackSurfaces.length; i++) {
if (mBlackSurfaces[i] != null) {
if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
" BLACK " + mBlackSurfaces[i].surface + ": DESTROY");
- mBlackSurfaces[i].surface.remove();
+ t.remove(mBlackSurfaces[i].surface);
mBlackSurfaces[i] = null;
}
}
+ t.apply();
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e099a4f0c91c..3e7fea2ac203 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1072,9 +1072,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// removing from parent.
token.getParent().removeChild(token);
}
- if (prevDc.mLastFocus == mCurrentFocus) {
- // The window has become the focus of this display, so it should not be notified
- // that it lost focus from the previous display.
+ if (token.hasChild(prevDc.mLastFocus)) {
+ // If the reparent window token contains previous display's last focus window, means
+ // it will end up to gain window focus on the target display, so it should not be
+ // notified that it lost focus from the previous display.
prevDc.mLastFocus = null;
}
}
@@ -4589,13 +4590,15 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
.show(mSplitScreenDividerAnchor);
scheduleAnimation();
} else {
- mAppAnimationLayer.remove();
+ mWmService.mTransactionFactory.make()
+ .remove(mAppAnimationLayer)
+ .remove(mBoostedAppAnimationLayer)
+ .remove(mHomeAppAnimationLayer)
+ .remove(mSplitScreenDividerAnchor)
+ .apply();
mAppAnimationLayer = null;
- mBoostedAppAnimationLayer.remove();
mBoostedAppAnimationLayer = null;
- mHomeAppAnimationLayer.remove();
mHomeAppAnimationLayer = null;
- mSplitScreenDividerAnchor.remove();
mSplitScreenDividerAnchor = null;
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index ed7dbd05853a..99a9db316c63 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -3622,7 +3622,8 @@ public class DisplayPolicy {
if (mScreenshotHelper != null) {
mScreenshotHelper.takeScreenshot(screenshotType,
mStatusBar != null && mStatusBar.isVisibleLw(),
- mNavigationBar != null && mNavigationBar.isVisibleLw(), mHandler);
+ mNavigationBar != null && mNavigationBar.isVisibleLw(),
+ mHandler, null /* completionConsumer */);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index a46fa13adf4e..207e8ef728eb 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -30,6 +30,7 @@ import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.os.Environment;
+import android.os.FileUtils;
import android.provider.Settings;
import android.util.AtomicFile;
import android.util.Slog;
@@ -64,6 +65,11 @@ import java.util.HashMap;
class DisplayWindowSettings {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayWindowSettings" : TAG_WM;
+ private static final String SYSTEM_DIRECTORY = "system";
+ private static final String DISPLAY_SETTINGS_FILE_NAME = "display_settings.xml";
+ private static final String VENDOR_DISPLAY_SETTINGS_PATH = "etc/" + DISPLAY_SETTINGS_FILE_NAME;
+ private static final String WM_DISPLAY_COMMIT_TAG = "wm-displays";
+
private static final int IDENTIFIER_UNIQUE_ID = 0;
private static final int IDENTIFIER_PORT = 1;
@IntDef(prefix = { "IDENTIFIER_" }, value = {
@@ -688,8 +694,26 @@ class DisplayWindowSettings {
private final AtomicFile mAtomicFile;
AtomicFileStorage() {
- final File folder = new File(Environment.getDataDirectory(), "system");
- mAtomicFile = new AtomicFile(new File(folder, "display_settings.xml"), "wm-displays");
+ final File folder = new File(Environment.getDataDirectory(), SYSTEM_DIRECTORY);
+ final File settingsFile = new File(folder, DISPLAY_SETTINGS_FILE_NAME);
+ // If display_settings.xml doesn't exist, try to copy the vendor's one instead
+ // in order to provide the vendor specific initialization.
+ if (!settingsFile.exists()) {
+ copyVendorSettings(settingsFile);
+ }
+ mAtomicFile = new AtomicFile(settingsFile, WM_DISPLAY_COMMIT_TAG);
+ }
+
+ private static void copyVendorSettings(File target) {
+ final File vendorFile = new File(Environment.getVendorDirectory(),
+ VENDOR_DISPLAY_SETTINGS_PATH);
+ if (vendorFile.canRead()) {
+ try {
+ FileUtils.copy(vendorFile, target);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to copy vendor display_settings.xml");
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
index b33b68a7a5b2..271db2895eac 100644
--- a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
+++ b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
@@ -110,7 +110,9 @@ class HighRefreshRateBlacklist {
private class OnPropertyChangedListener implements DeviceConfig.OnPropertyChangedListener {
public void onPropertyChanged(@NonNull String namespace, @NonNull String name,
@Nullable String value) {
- updateBlacklist(value);
+ if (KEY_HIGH_REFRESH_RATE_BLACKLIST.equals(name)) {
+ updateBlacklist(value);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index c3ea72f4c2fe..bb035d524f55 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -261,7 +261,7 @@ public class Letterbox {
public void remove() {
if (mSurface != null) {
- mSurface.remove();
+ new SurfaceControl.Transaction().remove(mSurface).apply();
mSurface = null;
}
if (mInputInterceptor != null) {
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index d58c61368f9a..ffbf68813d35 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -1667,7 +1667,8 @@ class RootActivityContainer extends ConfigurationContainer
<T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r,
@Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop) {
- return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */);
+ return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */,
+ -1 /* no realCallingPid */, -1 /* no realCallingUid */);
}
/**
@@ -1676,13 +1677,16 @@ class RootActivityContainer extends ConfigurationContainer
* @param r The activity we are trying to launch. Can be null.
* @param options The activity options used to the launch. Can be null.
* @param candidateTask The possible task the activity might be launched in. Can be null.
- * @params launchParams The resolved launch params to use.
+ * @param launchParams The resolved launch params to use.
+ * @param realCallingPid The pid from {@link ActivityStarter#setRealCallingPid}
+ * @param realCallingUid The uid from {@link ActivityStarter#setRealCallingUid}
*
* @return The stack to use for the launch or INVALID_STACK_ID.
*/
<T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r,
@Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop,
- @Nullable LaunchParamsController.LaunchParams launchParams) {
+ @Nullable LaunchParamsController.LaunchParams launchParams, int realCallingPid,
+ int realCallingUid) {
int taskId = INVALID_TASK_ID;
int displayId = INVALID_DISPLAY;
//Rect bounds = null;
@@ -1713,7 +1717,14 @@ class RootActivityContainer extends ConfigurationContainer
if (launchParams != null && launchParams.mPreferredDisplayId != INVALID_DISPLAY) {
displayId = launchParams.mPreferredDisplayId;
}
- if (displayId != INVALID_DISPLAY && canLaunchOnDisplay(r, displayId)) {
+ final boolean canLaunchOnDisplayFromStartRequest =
+ realCallingPid != 0 && realCallingUid > 0 && r != null
+ && mStackSupervisor.canPlaceEntityOnDisplay(displayId, realCallingPid,
+ realCallingUid, r.info);
+ // Checking if the activity's launch caller, or the realCallerId of the activity from
+ // start request (i.e. PendingIntent caller) is allowed to launch on the display.
+ if (displayId != INVALID_DISPLAY && (canLaunchOnDisplay(r, displayId)
+ || canLaunchOnDisplayFromStartRequest)) {
if (r != null) {
stack = (T) getValidLaunchStackOnDisplay(displayId, r, candidateTask, options,
launchParams);
@@ -2266,9 +2277,9 @@ class RootActivityContainer extends ConfigurationContainer
void getRunningTasks(int maxNum, List<ActivityManager.RunningTaskInfo> list,
@WindowConfiguration.ActivityType int ignoreActivityType,
@WindowConfiguration.WindowingMode int ignoreWindowingMode, int callingUid,
- boolean allowed) {
+ boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) {
mStackSupervisor.mRunningTasks.getTasks(maxNum, list, ignoreActivityType,
- ignoreWindowingMode, mActivityDisplays, callingUid, allowed);
+ ignoreWindowingMode, mActivityDisplays, callingUid, allowed, crossUser, profileIds);
}
void sendPowerHintForLaunchStartIfNeeded(boolean forceSend, ActivityRecord targetActivity) {
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 3bf437d38bcc..81a85476c53a 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration.ActivityType;
import android.app.WindowConfiguration.WindowingMode;
+import android.util.ArraySet;
import java.util.ArrayList;
import java.util.Comparator;
@@ -40,7 +41,7 @@ class RunningTasks {
void getTasks(int maxNum, List<RunningTaskInfo> list, @ActivityType int ignoreActivityType,
@WindowingMode int ignoreWindowingMode, ArrayList<ActivityDisplay> activityDisplays,
- int callingUid, boolean allowed) {
+ int callingUid, boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) {
// Return early if there are no tasks to fetch
if (maxNum <= 0) {
return;
@@ -55,7 +56,7 @@ class RunningTasks {
final ActivityStack stack = display.getChildAt(stackNdx);
mTmpStackTasks.clear();
stack.getRunningTasks(mTmpStackTasks, ignoreActivityType, ignoreWindowingMode,
- callingUid, allowed);
+ callingUid, allowed, crossUser, profileIds);
mTmpSortedSet.addAll(mTmpStackTasks);
}
}
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 0be9736e9d76..b94a7dc781e8 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -558,7 +558,7 @@ class ScreenRotationAnimation {
Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
mOriginalWidth*2, mOriginalHeight*2);
Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
- mCustomBlackFrame = new BlackFrame(t, outer, inner,
+ mCustomBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
SCREEN_FREEZE_LAYER_CUSTOM, mDisplayContent, false);
mCustomBlackFrame.setMatrix(t, mFrameInitialMatrix);
} catch (OutOfResourcesException e) {
@@ -589,7 +589,7 @@ class ScreenRotationAnimation {
mOriginalWidth*2, mOriginalHeight*2);
inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
}
- mExitingBlackFrame = new BlackFrame(t, outer, inner,
+ mExitingBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
SCREEN_FREEZE_LAYER_EXIT, mDisplayContent, mForceDefaultOrientation);
mExitingBlackFrame.setMatrix(t, mFrameInitialMatrix);
} catch (OutOfResourcesException e) {
@@ -602,7 +602,7 @@ class ScreenRotationAnimation {
Rect outer = new Rect(-finalWidth*1, -finalHeight*1,
finalWidth*2, finalHeight*2);
Rect inner = new Rect(0, 0, finalWidth, finalHeight);
- mEnteringBlackFrame = new BlackFrame(t, outer, inner,
+ mEnteringBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
SCREEN_FREEZE_LAYER_ENTER, mDisplayContent, false);
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
@@ -640,7 +640,7 @@ class ScreenRotationAnimation {
if (SHOW_TRANSACTIONS ||
SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
" FREEZE " + mSurfaceControl + ": DESTROY");
- mSurfaceControl.remove();
+ mService.mTransactionFactory.make().remove(mSurfaceControl).apply();
mSurfaceControl = null;
}
if (mCustomBlackFrame != null) {
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index f776062b31a1..4c50527dd67c 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -55,7 +55,8 @@ class TaskChangeNotificationController {
private static final int NOTIFY_SIZE_COMPAT_MODE_ACTIVITY_CHANGED_MSG = 20;
private static final int NOTIFY_BACK_PRESSED_ON_TASK_ROOT = 21;
private static final int NOTIFY_SINGLE_TASK_DISPLAY_DRAWN = 22;
- private static final int NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG = 23;
+ private static final int NOTIFY_SINGLE_TASK_DISPLAY_EMPTY = 23;
+ private static final int NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG = 24;
// Delay in notifying task stack change listeners (in millis)
private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -160,6 +161,10 @@ class TaskChangeNotificationController {
l.onSingleTaskDisplayDrawn(m.arg1);
};
+ private final TaskStackConsumer mNotifySingleTaskDisplayEmpty = (l, m) -> {
+ l.onSingleTaskDisplayEmpty(m.arg1);
+ };
+
private final TaskStackConsumer mNotifyTaskDisplayChanged = (l, m) -> {
l.onTaskDisplayChanged(m.arg1, m.arg2);
};
@@ -246,6 +251,9 @@ class TaskChangeNotificationController {
case NOTIFY_SINGLE_TASK_DISPLAY_DRAWN:
forAllRemoteListeners(mNotifySingleTaskDisplayDrawn, msg);
break;
+ case NOTIFY_SINGLE_TASK_DISPLAY_EMPTY:
+ forAllRemoteListeners(mNotifySingleTaskDisplayEmpty, msg);
+ break;
case NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG:
forAllRemoteListeners(mNotifyTaskDisplayChanged, msg);
break;
@@ -505,6 +513,17 @@ class TaskChangeNotificationController {
}
/**
+ * Notify listeners that the last task is removed from a single task display.
+ */
+ void notifySingleTaskDisplayEmpty(int displayId) {
+ final Message msg = mHandler.obtainMessage(
+ NOTIFY_SINGLE_TASK_DISPLAY_EMPTY,
+ displayId, 0 /* unused */);
+ forAllLocalListeners(mNotifySingleTaskDisplayEmpty, msg);
+ msg.sendToTarget();
+ }
+
+ /**
* Notify listeners that a task is reparented to another display.
*/
void notifyTaskDisplayChanged(int taskId, int newDisplayId) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 114a56feaf73..343a972801dd 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1012,7 +1012,7 @@ public class TaskStack extends WindowContainer<Task> implements
EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
if (mAnimationBackgroundSurface != null) {
- mAnimationBackgroundSurface.remove();
+ mWmService.mTransactionFactory.make().remove(mAnimationBackgroundSurface).apply();
mAnimationBackgroundSurface = null;
}
@@ -1747,6 +1747,11 @@ public class TaskStack extends WindowContainer<Task> implements
if (toBounds.width() == fromBounds.width()
&& toBounds.height() == fromBounds.height()) {
intendedAnimationType = BoundsAnimationController.BOUNDS;
+ } else if (!fromFullscreen && !toBounds.equals(fromBounds)) {
+ // intendedAnimationType may have been reset at the end of RecentsAnimation,
+ // force it to BOUNDS type if we know for certain we're animating to
+ // a different bounds, especially for expand and collapse of PiP window.
+ intendedAnimationType = BoundsAnimationController.BOUNDS;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ec970d2d3a5a..e1f85446de7b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1167,7 +1167,8 @@ public class WindowManagerService extends IWindowManager.Stub
new HandlerExecutor(mH), properties -> {
synchronized (mGlobalLock) {
final int exclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP,
- properties.getInt(KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0));
+ DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0));
final boolean excludedByPreQSticky = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_WINDOW_MANAGER,
KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 4cb546f107c7..e0a9af543f99 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -23,7 +23,6 @@ import static android.view.Display.INVALID_DISPLAY;
import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
-import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
@@ -553,14 +552,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
continue;
}
ActivityRecord topActivity = task.getTopActivity();
- if (topActivity == null) {
- continue;
- }
- // If an activity has just been started it will not yet be visible, but
- // is expected to be soon. We treat this as if it were already visible.
- // This ensures a subsequent activity can be started even before this one
- // becomes visible.
- if (topActivity.visible || topActivity.isState(INITIALIZING)) {
+ if (topActivity != null && topActivity.visible) {
return true;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 53bbd7010b5d..f37209bc6467 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -162,7 +162,7 @@ class WindowSurfaceController {
}
try {
if (mSurfaceControl != null) {
- mSurfaceControl.remove();
+ mTmpTransaction.remove(mSurfaceControl).apply();
}
} catch (RuntimeException e) {
Slog.w(TAG, "Error destroying surface in: " + this, e);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 16c60ca3997a..80535e496fbc 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -23,6 +23,7 @@ import static android.os.IServiceManager.DUMP_FLAG_PROTO;
import static android.view.Display.DEFAULT_DISPLAY;
import android.annotation.NonNull;
+import android.annotation.StringRes;
import android.app.ActivityThread;
import android.app.AppCompatCallbacks;
import android.app.INotificationManager;
@@ -39,6 +40,7 @@ import android.database.sqlite.SQLiteCompatibilityWalFlags;
import android.database.sqlite.SQLiteGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.net.ConnectivityModuleConnector;
+import android.net.Network;
import android.net.NetworkStackClient;
import android.os.BaseBundle;
import android.os.Binder;
@@ -1266,14 +1268,22 @@ public final class SystemServer {
startSystemCaptionsManagerService(context);
// App prediction manager service
- traceBeginAndSlog("StartAppPredictionService");
- mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS);
- traceEnd();
+ if (deviceHasConfigString(context, R.string.config_defaultAppPredictionService)) {
+ traceBeginAndSlog("StartAppPredictionService");
+ mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS);
+ traceEnd();
+ } else {
+ Slog.d(TAG, "AppPredictionService not defined by OEM");
+ }
// Content suggestions manager service
- traceBeginAndSlog("StartContentSuggestionsService");
- mSystemServiceManager.startService(CONTENT_SUGGESTIONS_SERVICE_CLASS);
- traceEnd();
+ if (deviceHasConfigString(context, R.string.config_defaultContentSuggestionsService)) {
+ traceBeginAndSlog("StartContentSuggestionsService");
+ mSystemServiceManager.startService(CONTENT_SUGGESTIONS_SERVICE_CLASS);
+ traceEnd();
+ } else {
+ Slog.d(TAG, "ContentSuggestionsService not defined by OEM");
+ }
traceBeginAndSlog("InitConnectivityModuleConnector");
try {
@@ -2264,10 +2274,13 @@ public final class SystemServer {
}, BOOT_TIMINGS_TRACE_LOG);
}
+ private boolean deviceHasConfigString(@NonNull Context context, @StringRes int resId) {
+ String serviceName = context.getString(resId);
+ return !TextUtils.isEmpty(serviceName);
+ }
+
private void startSystemCaptionsManagerService(@NonNull Context context) {
- String serviceName = context.getString(
- com.android.internal.R.string.config_defaultSystemCaptionsManagerService);
- if (TextUtils.isEmpty(serviceName)) {
+ if (!deviceHasConfigString(context, R.string.config_defaultSystemCaptionsManagerService)) {
Slog.d(TAG, "SystemCaptionsManagerService disabled because resource is not overlaid");
return;
}
@@ -2294,9 +2307,7 @@ public final class SystemServer {
// Then check if OEM overlaid the resource that defines the service.
if (!explicitlyEnabled) {
- final String serviceName = context
- .getString(com.android.internal.R.string.config_defaultContentCaptureService);
- if (TextUtils.isEmpty(serviceName)) {
+ if (!deviceHasConfigString(context, R.string.config_defaultContentCaptureService)) {
Slog.d(TAG, "ContentCaptureService disabled because resource is not overlaid");
return;
}
diff --git a/services/net/java/android/net/ConnectivityModuleConnector.java b/services/net/java/android/net/ConnectivityModuleConnector.java
index 19ade3394de7..62f2c35f339b 100644
--- a/services/net/java/android/net/ConnectivityModuleConnector.java
+++ b/services/net/java/android/net/ConnectivityModuleConnector.java
@@ -32,7 +32,7 @@ import android.os.IBinder;
import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.provider.Settings;
+import android.provider.DeviceConfig;
import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.Slog;
@@ -296,8 +296,6 @@ public class ConnectivityModuleConnector {
private synchronized void maybeCrashWithTerribleFailure(@NonNull String message,
@Nullable String packageName) {
logWtf(message, null);
- // Called DeviceConfig to minimize merge conflicts
- final DeviceConfigStub DeviceConfig = new DeviceConfigStub(mContext);
// uptime is monotonic even after a framework restart
final long uptime = SystemClock.elapsedRealtime();
final long now = System.currentTimeMillis();
@@ -417,36 +415,4 @@ public class ConnectivityModuleConnector {
// dump is thread-safe on SharedLog
mLog.dump(null, pw, null);
}
-
- /**
- * Stub class to replicate DeviceConfig behavior with minimal merge conflicts.
- */
- private class DeviceConfigStub {
- private final Context mContext;
-
- // Namespace is actually unused, but is here to replicate the final API.
- private static final String NAMESPACE_CONNECTIVITY = "connectivity";
-
- private DeviceConfigStub(Context context) {
- mContext = context;
- }
-
- private long getLong(
- @NonNull String namespace, @NonNull String key, long defaultVal) {
- // Temporary solution until DeviceConfig is available
- try {
- return Settings.Global.getLong(
- mContext.getContentResolver(), TAG + "_" + key, defaultVal);
- } catch (Throwable e) {
- logWtf("Could not obtain setting " + key, e);
- return defaultVal;
- }
- }
-
- private boolean getBoolean(
- @NonNull String namespace, @NonNull String key, boolean defaultVal) {
- // Temporary solution until DeviceConfig is available
- return getLong(namespace, key, defaultVal ? 1 : 0) != 0;
- }
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java
index e72e4601bbe8..c73be6f100cd 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java
@@ -35,6 +35,8 @@ import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.function.Consumer;
+
/**
* Tests for GlobalActionPerformer
*/
@@ -84,6 +86,6 @@ public class GlobalActionPerformerTest {
AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT);
verify(mMockScreenshotHelper).takeScreenshot(
eq(android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN), anyBoolean(),
- anyBoolean(), any(Handler.class));
+ anyBoolean(), any(Handler.class), any());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
index d5d32bdd00cc..376f5cd3ab47 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
@@ -18,7 +18,10 @@ package com.android.server.pm;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.opToName;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -39,7 +42,6 @@ import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.SuspendDialogInfo;
import android.content.res.Resources;
-import android.media.AudioAttributes;
import android.os.BaseBundle;
import android.os.Bundle;
import android.os.Handler;
@@ -551,28 +553,42 @@ public class SuspendPackagesTest {
}
@Test
- public void testAudioOpBlockedOnSuspend() throws Exception {
+ public void testCameraBlockedOnSuspend() throws Exception {
+ assertOpBlockedOnSuspend(OP_CAMERA);
+ }
+
+ @Test
+ public void testPlayAudioBlockedOnSuspend() throws Exception {
+ assertOpBlockedOnSuspend(OP_PLAY_AUDIO);
+ }
+
+ @Test
+ public void testRecordAudioBlockedOnSuspend() throws Exception {
+ assertOpBlockedOnSuspend(OP_RECORD_AUDIO);
+ }
+
+ private void assertOpBlockedOnSuspend(int code) throws Exception {
final IAppOpsService iAppOps = IAppOpsService.Stub.asInterface(
ServiceManager.getService(Context.APP_OPS_SERVICE));
final CountDownLatch latch = new CountDownLatch(1);
final IAppOpsCallback watcher = new IAppOpsCallback.Stub() {
@Override
public void opChanged(int op, int uid, String packageName) {
- if (op == OP_PLAY_AUDIO && packageName.equals(TEST_APP_PACKAGE_NAME)) {
+ if (op == code && packageName.equals(TEST_APP_PACKAGE_NAME)) {
latch.countDown();
}
}
};
- iAppOps.startWatchingMode(OP_PLAY_AUDIO, TEST_APP_PACKAGE_NAME, watcher);
+ iAppOps.startWatchingMode(code, TEST_APP_PACKAGE_NAME, watcher);
final int testPackageUid = mPackageManager.getPackageUid(TEST_APP_PACKAGE_NAME, 0);
- int audioOpMode = iAppOps.checkAudioOperation(OP_PLAY_AUDIO,
- AudioAttributes.USAGE_UNKNOWN, testPackageUid, TEST_APP_PACKAGE_NAME);
- assertEquals("Audio muted for unsuspended package", MODE_ALLOWED, audioOpMode);
+ int opMode = iAppOps.checkOperation(code, testPackageUid, TEST_APP_PACKAGE_NAME);
+ assertEquals("Op " + opToName(code) + " disallowed for unsuspended package", MODE_ALLOWED,
+ opMode);
suspendTestPackage(null, null, null);
assertTrue("AppOpsWatcher did not callback", latch.await(5, TimeUnit.SECONDS));
- audioOpMode = iAppOps.checkAudioOperation(OP_PLAY_AUDIO,
- AudioAttributes.USAGE_UNKNOWN, testPackageUid, TEST_APP_PACKAGE_NAME);
- assertEquals("Audio not muted for suspended package", MODE_IGNORED, audioOpMode);
+ opMode = iAppOps.checkOperation(code, testPackageUid, TEST_APP_PACKAGE_NAME);
+ assertEquals("Op " + opToName(code) + " allowed for suspended package", MODE_IGNORED,
+ opMode);
iAppOps.stopWatchingMode(watcher);
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
index 273a9e66e55b..7459c4b0610e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
@@ -86,7 +86,7 @@ public class BubbleExtractorTest extends UiServiceTestCase {
BubbleExtractor extractor = new BubbleExtractor();
extractor.setConfig(mConfig);
- when(mConfig.bubblesEnabled(mUser)).thenReturn(true);
+ when(mConfig.bubblesEnabled()).thenReturn(true);
when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true);
NotificationRecord r = getNotificationRecord(false, IMPORTANCE_UNSPECIFIED);
@@ -100,7 +100,7 @@ public class BubbleExtractorTest extends UiServiceTestCase {
BubbleExtractor extractor = new BubbleExtractor();
extractor.setConfig(mConfig);
- when(mConfig.bubblesEnabled(mUser)).thenReturn(true);
+ when(mConfig.bubblesEnabled()).thenReturn(true);
when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(false);
NotificationRecord r = getNotificationRecord(true, IMPORTANCE_HIGH);
@@ -114,7 +114,7 @@ public class BubbleExtractorTest extends UiServiceTestCase {
BubbleExtractor extractor = new BubbleExtractor();
extractor.setConfig(mConfig);
- when(mConfig.bubblesEnabled(mUser)).thenReturn(true);
+ when(mConfig.bubblesEnabled()).thenReturn(true);
when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true);
NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED);
@@ -128,7 +128,7 @@ public class BubbleExtractorTest extends UiServiceTestCase {
BubbleExtractor extractor = new BubbleExtractor();
extractor.setConfig(mConfig);
- when(mConfig.bubblesEnabled(mUser)).thenReturn(true);
+ when(mConfig.bubblesEnabled()).thenReturn(true);
when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(false);
NotificationRecord r = getNotificationRecord(false, IMPORTANCE_UNSPECIFIED);
@@ -142,7 +142,7 @@ public class BubbleExtractorTest extends UiServiceTestCase {
BubbleExtractor extractor = new BubbleExtractor();
extractor.setConfig(mConfig);
- when(mConfig.bubblesEnabled(mUser)).thenReturn(false);
+ when(mConfig.bubblesEnabled()).thenReturn(false);
when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true);
NotificationRecord r = getNotificationRecord(true, IMPORTANCE_HIGH);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 0c31b143df57..389b68a7d4b7 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -20,6 +20,7 @@ import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREG
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
import static android.app.Notification.CATEGORY_CALL;
+import static android.app.Notification.FLAG_AUTO_CANCEL;
import static android.app.Notification.FLAG_BUBBLE;
import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.NotificationManager.EXTRA_BLOCKED_STATE;
@@ -420,7 +421,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
private void setUpPrefsForBubbles(boolean globalEnabled, boolean pkgEnabled,
boolean channelEnabled) {
mService.setPreferencesHelper(mPreferencesHelper);
- when(mPreferencesHelper.bubblesEnabled(any())).thenReturn(globalEnabled);
+ when(mPreferencesHelper.bubblesEnabled()).thenReturn(globalEnabled);
when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(pkgEnabled);
when(mPreferencesHelper.getNotificationChannel(
anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
@@ -439,14 +440,22 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
return sbn;
}
+
private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
String groupKey, boolean isSummary) {
+ return generateNotificationRecord(channel, id, groupKey, isSummary, false /* isBubble */);
+ }
+
+ private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
+ String groupKey, boolean isSummary, boolean isBubble) {
Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon)
.setGroup(groupKey)
.setGroupSummary(isSummary);
-
+ if (isBubble) {
+ nb.setBubbleMetadata(getBasicBubbleMetadataBuilder().build());
+ }
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", mUid, 0,
nb.build(), new UserHandle(mUid), null, 0);
return new NotificationRecord(mContext, sbn, channel);
@@ -542,6 +551,52 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setIcon(Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon));
}
+ private NotificationRecord addGroupWithBubblesAndValidateAdded(boolean summaryAutoCancel)
+ throws RemoteException {
+
+ // Notification that has bubble metadata
+ NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel, 1,
+ "BUBBLE_GROUP", false /* isSummary */, true /* isBubble */);
+
+ // Make the package foreground so that we're allowed to be a bubble
+ when(mActivityManager.getPackageImportance(nrBubble.sbn.getPackageName())).thenReturn(
+ IMPORTANCE_FOREGROUND);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
+ nrBubble.sbn.getId(), nrBubble.sbn.getNotification(), nrBubble.sbn.getUserId());
+ waitForIdle();
+
+ // Make sure we are a bubble
+ StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
+ assertEquals(1, notifsAfter.length);
+ assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0);
+
+ // Plain notification without bubble metadata
+ NotificationRecord nrPlain = generateNotificationRecord(mTestNotificationChannel, 2,
+ "BUBBLE_GROUP", false /* isSummary */, false /* isBubble */);
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
+ nrPlain.sbn.getId(), nrPlain.sbn.getNotification(), nrPlain.sbn.getUserId());
+ waitForIdle();
+
+ notifsAfter = mBinderService.getActiveNotifications(PKG);
+ assertEquals(2, notifsAfter.length);
+
+ // Summary notification for both of those
+ NotificationRecord nrSummary = generateNotificationRecord(mTestNotificationChannel, 3,
+ "BUBBLE_GROUP", true /* isSummary */, false /* isBubble */);
+ if (summaryAutoCancel) {
+ nrSummary.getNotification().flags |= FLAG_AUTO_CANCEL;
+ }
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
+ nrSummary.sbn.getId(), nrSummary.sbn.getNotification(), nrSummary.sbn.getUserId());
+ waitForIdle();
+
+ notifsAfter = mBinderService.getActiveNotifications(PKG);
+ assertEquals(3, notifsAfter.length);
+
+ return nrSummary;
+ }
+
@Test
public void testCreateNotificationChannels_SingleChannel() throws Exception {
final NotificationChannel channel =
@@ -1508,14 +1563,22 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testUpdateAppNotifyCreatorBlock() throws Exception {
mService.setPreferencesHelper(mPreferencesHelper);
- mBinderService.setNotificationsEnabledForPackage(PKG, 0, false);
+ mBinderService.setNotificationsEnabledForPackage(PKG, 0, true);
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
captor.getValue().getAction());
assertEquals(PKG, captor.getValue().getPackage());
- assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
+ assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
+ }
+
+ @Test
+ public void testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting() throws Exception {
+ mService.setPreferencesHelper(mPreferencesHelper);
+
+ mBinderService.setNotificationsEnabledForPackage(PKG, 0, false);
+ verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
}
@Test
@@ -5082,4 +5145,162 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertEquals(1, notifsAfter.length);
assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
}
+
+ @Test
+ public void testNotificationBubbles_flagAutoExpandForeground_fails_notForeground()
+ throws Exception {
+ // Bubbles are allowed!
+ setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
+
+ // Give it bubble metadata
+ Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder()
+ .setSuppressNotification(true)
+ .setAutoExpandBubble(true).build();
+ // Give it a person
+ Person person = new Person.Builder()
+ .setName("bubblebot")
+ .build();
+ // It needs remote input to be bubble-able
+ RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
+ PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+ Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
+ Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
+ inputIntent).addRemoteInput(remoteInput)
+ .build();
+ // Make it messaging style
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .setContentTitle("foo")
+ .setBubbleMetadata(data)
+ .setStyle(new Notification.MessagingStyle(person)
+ .setConversationTitle("Bubble Chat")
+ .addMessage("Hello?",
+ SystemClock.currentThreadTimeMillis() - 300000, person)
+ .addMessage("Is it me you're looking for?",
+ SystemClock.currentThreadTimeMillis(), person)
+ )
+ .setActions(replyAction)
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0,
+ nb.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ // Ensure we're not foreground
+ when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn(
+ IMPORTANCE_VISIBLE);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
+ nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+ waitForIdle();
+
+ // yes allowed, yes messaging, yes bubble
+ Notification notif = mService.getNotificationRecord(sbn.getKey()).getNotification();
+ assertTrue(notif.isBubbleNotification());
+
+ // Our flags should have failed since we're not foreground
+ assertFalse(notif.getBubbleMetadata().getAutoExpandBubble());
+ assertFalse(notif.getBubbleMetadata().isNotificationSuppressed());
+ }
+
+ @Test
+ public void testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground()
+ throws RemoteException {
+ // Bubbles are allowed!
+ setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
+
+ // Give it bubble metadata
+ Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder()
+ .setSuppressNotification(true)
+ .setAutoExpandBubble(true).build();
+ // Give it a person
+ Person person = new Person.Builder()
+ .setName("bubblebot")
+ .build();
+ // It needs remote input to be bubble-able
+ RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
+ PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+ Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
+ Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
+ inputIntent).addRemoteInput(remoteInput)
+ .build();
+ // Make it messaging style
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .setContentTitle("foo")
+ .setBubbleMetadata(data)
+ .setStyle(new Notification.MessagingStyle(person)
+ .setConversationTitle("Bubble Chat")
+ .addMessage("Hello?",
+ SystemClock.currentThreadTimeMillis() - 300000, person)
+ .addMessage("Is it me you're looking for?",
+ SystemClock.currentThreadTimeMillis(), person)
+ )
+ .setActions(replyAction)
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0,
+ nb.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ // Ensure we are in the foreground
+ when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn(
+ IMPORTANCE_FOREGROUND);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
+ nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+ waitForIdle();
+
+ // yes allowed, yes messaging, yes bubble
+ Notification notif = mService.getNotificationRecord(sbn.getKey()).getNotification();
+ assertTrue(notif.isBubbleNotification());
+
+ // Our flags should have failed since we are foreground
+ assertTrue(notif.getBubbleMetadata().getAutoExpandBubble());
+ assertTrue(notif.getBubbleMetadata().isNotificationSuppressed());
+ }
+
+ @Test
+ public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryDismissed()
+ throws Exception {
+ // Bubbles are allowed!
+ setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
+
+ NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded(
+ true /* summaryAutoCancel */);
+
+ // Dismiss summary
+ final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2,
+ true);
+ mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, nrSummary.sbn.getTag(),
+ nrSummary.sbn.getId(), nrSummary.getUserId(), nrSummary.getKey(),
+ NotificationStats.DISMISSAL_SHADE,
+ NotificationStats.DISMISS_SENTIMENT_NEUTRAL, nv);
+ waitForIdle();
+
+ // The bubble should still exist
+ StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
+ assertEquals(1, notifsAfter.length);
+ }
+
+ @Test
+ public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryClicked()
+ throws Exception {
+ // Bubbles are allowed!
+ setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
+
+ NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded(
+ true /* summaryAutoCancel */);
+
+ // Click summary
+ final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2,
+ true);
+ mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(),
+ nrSummary.getKey(), nv);
+ waitForIdle();
+
+ // The bubble should still exist
+ StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
+ assertEquals(1, notifsAfter.length);
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 8f8b746b59d4..80439cf66387 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -22,6 +22,8 @@ import static android.app.NotificationManager.IMPORTANCE_MAX;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT;
+
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.fail;
@@ -58,7 +60,9 @@ import android.net.Uri;
import android.os.Build;
import android.os.UserHandle;
import android.provider.Settings;
+import android.provider.Settings.Global;
import android.provider.Settings.Secure;
+
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.TestableContentResolver;
import android.util.ArrayMap;
@@ -152,8 +156,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
contentResolver.setFallbackToExisting(false);
Secure.putIntForUser(contentResolver,
Secure.NOTIFICATION_BADGING, 1, UserHandle.getUserId(UID_N_MR1));
- Secure.putIntForUser(contentResolver,
- Secure.NOTIFICATION_BUBBLES, 1, UserHandle.getUserId(UID_N_MR1));
+ Global.putInt(contentResolver, Global.NOTIFICATION_BUBBLES, 1);
ContentProvider testContentProvider = mock(ContentProvider.class);
when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider);
@@ -1948,42 +1951,18 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testBubblesOverrideTrue() {
- Secure.putIntForUser(getContext().getContentResolver(),
- Secure.NOTIFICATION_BUBBLES, 1,
- USER.getIdentifier());
+ Global.putInt(getContext().getContentResolver(),
+ Global.NOTIFICATION_BUBBLES, 1);
mHelper.updateBubblesEnabled(); // would be called by settings observer
- assertTrue(mHelper.bubblesEnabled(USER));
+ assertTrue(mHelper.bubblesEnabled());
}
@Test
public void testBubblesOverrideFalse() {
- Secure.putIntForUser(getContext().getContentResolver(),
- Secure.NOTIFICATION_BUBBLES, 0,
- USER.getIdentifier());
- mHelper.updateBubblesEnabled(); // would be called by settings observer
- assertFalse(mHelper.bubblesEnabled(USER));
- }
-
- @Test
- public void testBubblesForUserAll() {
- try {
- mHelper.bubblesEnabled(UserHandle.ALL);
- } catch (Exception e) {
- fail("just don't throw");
- }
- }
-
- @Test
- public void testBubblesOverrideUserIsolation() {
- Secure.putIntForUser(getContext().getContentResolver(),
- Secure.NOTIFICATION_BUBBLES, 0,
- USER.getIdentifier());
- Secure.putIntForUser(getContext().getContentResolver(),
- Secure.NOTIFICATION_BUBBLES, 1,
- USER2.getIdentifier());
+ Global.putInt(getContext().getContentResolver(),
+ Global.NOTIFICATION_BUBBLES, 0);
mHelper.updateBubblesEnabled(); // would be called by settings observer
- assertFalse(mHelper.bubblesEnabled(USER));
- assertTrue(mHelper.bubblesEnabled(USER2));
+ assertFalse(mHelper.bubblesEnabled());
}
@Test
@@ -2690,4 +2669,51 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertFalse(mHelper.areBubblesAllowed(PKG_O, UID_O));
verify(mHandler, times(1)).requestSort();
}
+
+ @Test
+ public void testTooManyChannels() {
+ for (int i = 0; i < NOTIFICATION_CHANNEL_COUNT_LIMIT; i++) {
+ NotificationChannel channel = new NotificationChannel(String.valueOf(i),
+ String.valueOf(i), NotificationManager.IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true);
+ }
+ try {
+ NotificationChannel channel = new NotificationChannel(
+ String.valueOf(NOTIFICATION_CHANNEL_COUNT_LIMIT),
+ String.valueOf(NOTIFICATION_CHANNEL_COUNT_LIMIT),
+ NotificationManager.IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true);
+ fail("Allowed to create too many notification channels");
+ } catch (IllegalStateException e) {
+ // great
+ }
+ }
+
+ @Test
+ public void testTooManyChannels_xml() throws Exception {
+ String extraChannel = "EXTRA";
+ String extraChannel1 = "EXTRA1";
+
+ // create first... many... directly so we don't need a big xml blob in this test
+ for (int i = 0; i < NOTIFICATION_CHANNEL_COUNT_LIMIT; i++) {
+ NotificationChannel channel = new NotificationChannel(String.valueOf(i),
+ String.valueOf(i), NotificationManager.IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true);
+ }
+
+ final String xml = "<ranking version=\"1\">\n"
+ + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
+ + "<channel id=\"" + extraChannel + "\" name=\"hi\" importance=\"3\"/>"
+ + "<channel id=\"" + extraChannel1 + "\" name=\"hi\" importance=\"3\"/>"
+ + "</package>"
+ + "</ranking>";
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
+ null);
+ parser.nextTag();
+ mHelper.readXml(parser, false, UserHandle.USER_ALL);
+
+ assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel, true));
+ assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel1, true));
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 3d944671ef25..07d9f803d9fa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -341,7 +341,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
doReturn(stack).when(mRootActivityContainer)
.getLaunchStack(any(), any(), any(), anyBoolean());
doReturn(stack).when(mRootActivityContainer)
- .getLaunchStack(any(), any(), any(), anyBoolean(), any());
+ .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt());
}
// Set up mock package manager internal and make sure no unmocked methods are called
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index ecf3acd32d4f..84bdecb86826 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -40,6 +40,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
+import static org.mockito.ArgumentMatchers.eq;
+
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.AppOpsManager;
@@ -72,6 +74,7 @@ import com.android.server.am.ActivityManagerService;
import com.android.server.am.PendingIntentController;
import com.android.server.appop.AppOpsService;
import com.android.server.firewall.IntentFirewall;
+import com.android.server.pm.UserManagerService;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.wm.TaskRecord.TaskRecordFactory;
@@ -92,6 +95,7 @@ import java.util.function.Consumer;
*/
class ActivityTestsBase {
private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
+ private static final int[] TEST_USER_PROFILE_IDS = {};
@Rule
public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
@@ -204,6 +208,8 @@ class ActivityTestsBase {
private ActivityStack mStack;
private int mActivityFlags;
private int mLaunchMode;
+ private int mLaunchedFromPid;
+ private int mLaunchedFromUid;
ActivityBuilder(ActivityTaskManagerService service) {
mService = service;
@@ -254,6 +260,16 @@ class ActivityTestsBase {
return this;
}
+ ActivityBuilder setLaunchedFromPid(int pid) {
+ mLaunchedFromPid = pid;
+ return this;
+ }
+
+ ActivityBuilder setLaunchedFromUid(int uid) {
+ mLaunchedFromUid = uid;
+ return this;
+ }
+
ActivityRecord build() {
if (mComponent == null) {
final int id = sCurrentActivityId++;
@@ -281,10 +297,11 @@ class ActivityTestsBase {
aInfo.launchMode = mLaunchMode;
final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
- 0 /* launchedFromPid */, 0, null, intent, null,
- aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */,
- 0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */,
- mService.mStackSupervisor, null /* options */, null /* sourceRecord */);
+ mLaunchedFromPid /* launchedFromPid */, mLaunchedFromUid /* launchedFromUid */,
+ null, intent, null, aInfo /*aInfo*/, new Configuration(), null /* resultTo */,
+ null /* resultWho */, 0 /* reqCode */, false /*componentSpecified*/,
+ false /* rootVoiceInteraction */, mService.mStackSupervisor,
+ null /* options */, null /* sourceRecord */);
spyOn(activity);
activity.mAppWindowToken = mock(AppWindowToken.class);
doCallRealMethod().when(activity.mAppWindowToken).getOrientationIgnoreVisibility();
@@ -471,6 +488,11 @@ class ActivityTestsBase {
// allow background activity starts by default
doReturn(true).when(this).isBackgroundActivityStartsEnabled();
doNothing().when(this).updateCpuStats();
+
+ // UserManager
+ final UserManagerService ums = mock(UserManagerService.class);
+ doReturn(ums).when(this).getUserManager();
+ doReturn(TEST_USER_PROFILE_IDS).when(ums).getProfileIds(anyInt(), eq(true));
}
void setup(IntentFirewall intentFirewall, PendingIntentController intentController,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index 292a05bd966a..a98f79cb5369 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -169,7 +169,7 @@ public class DimmerTests extends WindowTestsBase {
mDimmer.updateDims(mTransaction, new Rect());
verify(mTransaction).show(getDimLayer());
- verify(dimLayer, never()).remove();
+ verify(mTransaction, never()).remove(dimLayer);
}
@Test
@@ -231,7 +231,7 @@ public class DimmerTests extends WindowTestsBase {
mDimmer.updateDims(mTransaction, new Rect());
verify(mTransaction).show(dimLayer);
- verify(dimLayer, never()).remove();
+ verify(mTransaction, never()).remove(dimLayer);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index a1999c901702..e4f614d38c82 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -62,6 +62,7 @@ import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
+import android.util.ArraySet;
import android.util.MutableLong;
import android.util.SparseBooleanArray;
@@ -952,7 +953,6 @@ public class RecentTasksTest extends ActivityTestsBase {
public void testRecentsComponent_allowApiAccessWithoutPermissions() {
doReturn(PackageManager.PERMISSION_DENIED).when(mTestService)
.checkGetTasksPermission(anyString(), anyInt(), anyInt());
-
// Set the recents component and ensure that the following calls do not fail
mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.GRANT);
doTestRecentTasksApis(true /* expectNoSecurityException */);
@@ -1301,10 +1301,10 @@ public class RecentTasksTest extends ActivityTestsBase {
@Override
void getTasks(int maxNum, List<RunningTaskInfo> list, int ignoreActivityType,
int ignoreWindowingMode, ArrayList<ActivityDisplay> activityDisplays,
- int callingUid, boolean allowed) {
+ int callingUid, boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) {
mLastAllowed = allowed;
super.getTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, activityDisplays,
- callingUid, allowed);
+ callingUid, allowed, crossUser, profileIds);
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 8d2c3dd80538..baf1b0821982 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.TYPE_VIRTUAL;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -61,6 +62,7 @@ import android.content.res.Resources;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;
+import android.view.DisplayInfo;
import androidx.test.filters.MediumTest;
@@ -817,6 +819,41 @@ public class RootActivityContainerTests extends ActivityTestsBase {
}
/**
+ * Test that {@link RootActivityContainer#getLaunchStack} with the real caller id will get the
+ * expected stack when requesting the activity launch on the secondary display.
+ */
+ @Test
+ public void testGetLaunchStackWithRealCallerId() {
+ // Create a non-system owned virtual display.
+ final DisplayInfo info = new DisplayInfo();
+ mSupervisor.mService.mContext.getDisplay().getDisplayInfo(info);
+ info.type = TYPE_VIRTUAL;
+ info.ownerUid = 100;
+ final TestActivityDisplay secondaryDisplay = createNewActivityDisplay(info);
+ mRootActivityContainer.addChild(secondaryDisplay, POSITION_TOP);
+
+ // Create an activity with specify the original launch pid / uid.
+ final ActivityRecord r = new ActivityBuilder(mService).setLaunchedFromPid(200)
+ .setLaunchedFromUid(200).build();
+
+ // Simulate ActivityStarter to find a launch stack for requesting the activity to launch
+ // on the secondary display with realCallerId.
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(secondaryDisplay.mDisplayId);
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId,
+ 300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info);
+ final ActivityStack result = mRootActivityContainer.getLaunchStack(r, options,
+ null /* task */, true /* onTop */, null, 300 /* test realCallerPid */,
+ 300 /* test realCallerUid */);
+
+ // Assert that the stack is returned as expected.
+ assertNotNull(result);
+ assertEquals("The display ID of the stack should same as secondary display ",
+ secondaryDisplay.mDisplayId, result.mDisplayId);
+ }
+
+ /**
* Mock {@link RootActivityContainerTests#resolveHomeActivity} for returning consistent activity
* info for test cases (the original implementation will resolve from the real package manager).
*/
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index dc964806b7a9..3e316f674dbf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -29,6 +29,7 @@ import static org.junit.Assert.assertEquals;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.ComponentName;
import android.platform.test.annotations.Presubmit;
+import android.util.ArraySet;
import androidx.test.filters.MediumTest;
@@ -45,6 +46,8 @@ import java.util.ArrayList;
@Presubmit
public class RunningTasksTest extends ActivityTestsBase {
+ private static final ArraySet<Integer> PROFILE_IDS = new ArraySet<>();
+
private RunningTasks mRunningTasks;
@Before
@@ -77,7 +80,8 @@ public class RunningTasksTest extends ActivityTestsBase {
final int numFetchTasks = 5;
ArrayList<RunningTaskInfo> tasks = new ArrayList<>();
mRunningTasks.getTasks(5, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED,
- displays, -1 /* callingUid */, true /* allowed */);
+ displays, -1 /* callingUid */, true /* allowed */, true /*crossUser */,
+ PROFILE_IDS);
assertThat(tasks).hasSize(numFetchTasks);
for (int i = 0; i < numFetchTasks; i++) {
assertEquals(numTasks - i - 1, tasks.get(i).id);
@@ -87,7 +91,8 @@ public class RunningTasksTest extends ActivityTestsBase {
// and does not crash
tasks.clear();
mRunningTasks.getTasks(100, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED,
- displays, -1 /* callingUid */, true /* allowed */);
+ displays, -1 /* callingUid */, true /* allowed */, true /* crossUser */,
+ PROFILE_IDS);
assertThat(tasks).hasSize(numTasks);
for (int i = 0; i < numTasks; i++) {
assertEquals(numTasks - i - 1, tasks.get(i).id);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index 19fd93fee5f0..6e41118997ac 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -271,6 +271,54 @@ public class TaskStackChangedListenerTest {
waitForCallback(singleTaskDisplayDrawnLatch);
}
+ @Test
+ public void testSingleTaskDisplayEmpty() throws Exception {
+ final Instrumentation instrumentation = getInstrumentation();
+
+ final CountDownLatch activityViewReadyLatch = new CountDownLatch(1);
+ final CountDownLatch activityViewDestroyedLatch = new CountDownLatch(1);
+ final CountDownLatch singleTaskDisplayDrawnLatch = new CountDownLatch(1);
+ final CountDownLatch singleTaskDisplayEmptyLatch = new CountDownLatch(1);
+
+ registerTaskStackChangedListener(new TaskStackListener() {
+ @Override
+ public void onSingleTaskDisplayDrawn(int displayId) throws RemoteException {
+ singleTaskDisplayDrawnLatch.countDown();
+ }
+ @Override
+ public void onSingleTaskDisplayEmpty(int displayId)
+ throws RemoteException {
+ singleTaskDisplayEmptyLatch.countDown();
+ }
+ });
+ final ActivityViewTestActivity activity =
+ (ActivityViewTestActivity) startTestActivity(ActivityViewTestActivity.class);
+ final ActivityView activityView = activity.getActivityView();
+ activityView.setCallback(new ActivityView.StateCallback() {
+ @Override
+ public void onActivityViewReady(ActivityView view) {
+ activityViewReadyLatch.countDown();
+ }
+
+ @Override
+ public void onActivityViewDestroyed(ActivityView view) {
+ activityViewDestroyedLatch.countDown();
+ }
+ });
+ waitForCallback(activityViewReadyLatch);
+
+ final Context context = instrumentation.getContext();
+ Intent intent = new Intent(context, ActivityInActivityView.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ activityView.startActivity(intent);
+ waitForCallback(singleTaskDisplayDrawnLatch);
+ assertEquals(1, singleTaskDisplayEmptyLatch.getCount());
+
+ activityView.release();
+ waitForCallback(activityViewDestroyedLatch);
+ waitForCallback(singleTaskDisplayEmptyLatch);
+ }
+
/**
* Starts the provided activity and returns the started instance.
*/
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index b93c994f4d8f..acfc2ea3d402 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -114,16 +114,12 @@ public class WindowContainerTests extends WindowTestsBase {
@Test
public void testAddChildSetsSurfacePosition() {
try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) {
-
- final SurfaceControl.Transaction transaction = mock(SurfaceControl.Transaction.class);
- mWm.mTransactionFactory = () -> transaction;
-
WindowContainer child = new WindowContainer(mWm);
child.setBounds(1, 1, 10, 10);
- verify(transaction, never()).setPosition(any(), anyFloat(), anyFloat());
+ verify(mTransaction, never()).setPosition(any(), anyFloat(), anyFloat());
top.addChild(child, 0);
- verify(transaction, times(1)).setPosition(any(), eq(1.f), eq(1.f));
+ verify(mTransaction, times(1)).setPosition(any(), eq(1.f), eq(1.f));
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 99337565e128..735b9a1dcf2e 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -325,9 +325,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
false /* Don't notify for synchronous calls */);
// Initialize power save, call active state monitoring logic.
- if (status == STATUS_OK && !mRecognitionRequested) {
+ if (status == STATUS_OK) {
initializeTelephonyAndPowerStateListeners();
- mRecognitionRequested = true;
}
return status;
@@ -481,6 +480,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
if (unloadModel && modelData.isModelLoaded()) {
Slog.d(TAG, "Unloading previously loaded stale model.");
+ if (mModule == null) {
+ return STATUS_ERROR;
+ }
status = mModule.unloadSoundModel(modelData.getHandle());
MetricsLogger.count(mContext, "sth_unloading_stale_model", 1);
if (status != SoundTrigger.STATUS_OK) {
@@ -550,6 +552,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
}
+ if (mModule == null) {
+ return STATUS_ERROR;
+ }
int status = mModule.unloadSoundModel(modelData.getHandle());
if (status != SoundTrigger.STATUS_OK) {
Slog.w(TAG, "unloadGenericSoundModel() call failed with " + status);
@@ -878,6 +883,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
mContext.unregisterReceiver(mPowerSaveModeListener);
mPowerSaveModeListener = null;
}
+ mRecognitionRequested = false;
}
// Clears state for all models (generic and keyphrase).
@@ -924,6 +930,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
private void initializeTelephonyAndPowerStateListeners() {
+ if (mRecognitionRequested) {
+ return;
+ }
long token = Binder.clearCallingIdentity();
try {
// Get the current call state synchronously for the first recognition.
@@ -941,6 +950,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
mIsPowerSaveMode = mPowerManager.getPowerSaveState(ServiceType.SOUND)
.batterySaverEnabled;
+
+ mRecognitionRequested = true;
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -987,6 +998,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
if (exception != null) {
Slog.e(TAG, "forceStopAndUnloadModel", exception);
}
+ if (mModule == null) {
+ return;
+ }
if (modelData.isModelStarted()) {
Slog.d(TAG, "Stopping previously started dangling model " + modelData.getHandle());
if (mModule.stopRecognition(modelData.getHandle()) != STATUS_OK) {
@@ -1093,6 +1107,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// a recognition include: no active phone call or not being in a power save mode. Also,
// the native service should be enabled.
private boolean isRecognitionAllowed() {
+ // if mRecognitionRequested is false, call and power state listeners are not registered so
+ // we read current state directly from services
+ if (!mRecognitionRequested) {
+ mCallActive = mTelephonyManager.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK;
+ mIsPowerSaveMode =
+ mPowerManager.getPowerSaveState(ServiceType.SOUND).batterySaverEnabled;
+ }
return !mCallActive && !mServiceDisabled && !mIsPowerSaveMode;
}
@@ -1116,6 +1137,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
return STATUS_OK;
}
+ if (mModule == null) {
+ return STATUS_ERROR;
+ }
int status = mModule.startRecognition(handle, config);
if (status != SoundTrigger.STATUS_OK) {
Slog.w(TAG, "startRecognition failed with " + status);
@@ -1152,8 +1176,11 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
private int stopRecognitionLocked(ModelData modelData, boolean notify) {
- IRecognitionStatusCallback callback = modelData.getCallback();
+ if (mModule == null) {
+ return STATUS_ERROR;
+ }
+ IRecognitionStatusCallback callback = modelData.getCallback();
// Stop recognition.
int status = STATUS_OK;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index e1ffb0f179f8..46d7509b43ca 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1281,9 +1281,12 @@ public class VoiceInteractionManagerService extends SystemService {
RoleObserver(@NonNull @CallbackExecutor Executor executor) {
mRm.addOnRoleHoldersChangedListenerAsUser(executor, this, UserHandle.ALL);
- UserHandle currentUser = UserHandle.of(LocalServices.getService(
- ActivityManagerInternal.class).getCurrentUserId());
- onRoleHoldersChanged(RoleManager.ROLE_ASSISTANT, currentUser);
+ // Sync only if assistant role has been initialized.
+ if (mRm.isRoleAvailable(RoleManager.ROLE_ASSISTANT)) {
+ UserHandle currentUser = UserHandle.of(LocalServices.getService(
+ ActivityManagerInternal.class).getCurrentUserId());
+ onRoleHoldersChanged(RoleManager.ROLE_ASSISTANT, currentUser);
+ }
}
private @NonNull String getDefaultRecognizer(@NonNull UserHandle user) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index f16dec6fb670..0ff92739f8b6 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -194,7 +194,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
if (!mFullyBound) {
mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
Context.BIND_AUTO_CREATE | Context.BIND_TREAT_LIKE_ACTIVITY
- | Context.BIND_FOREGROUND_SERVICE
+ | Context.BIND_SCHEDULE_LIKE_TOP_APP
| Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS,
new UserHandle(mUser));
}