summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp2
-rw-r--r--apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java44
-rw-r--r--core/java/android/app/ActivityThread.java7
-rw-r--r--core/java/android/app/IApplicationThread.aidl2
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java5
-rw-r--r--core/java/android/content/Context.java6
-rw-r--r--core/java/android/content/Intent.java22
-rw-r--r--core/java/android/os/ExternalVibration.java29
-rw-r--r--core/java/android/provider/DeviceConfigInterface.java (renamed from services/core/java/com/android/server/utils/DeviceConfigInterface.java)85
-rw-r--r--core/java/android/view/InsetsSourceControl.java9
-rw-r--r--core/java/android/window/ITaskFragmentOrganizerController.aidl14
-rw-r--r--core/java/android/window/TaskFragmentOrganizer.java29
-rw-r--r--core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java30
-rw-r--r--core/java/com/android/internal/app/SuspendedAppActivity.java23
-rw-r--r--core/java/com/android/internal/inputmethod/IIntResultCallback.aidl24
-rw-r--r--core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java75
-rw-r--r--core/java/com/android/internal/inputmethod/ThrowableHolder.aidl19
-rw-r--r--core/java/com/android/internal/inputmethod/ThrowableHolder.java91
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java92
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogGroup.java2
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/res/res/xml/sms_short_codes.xml2
-rw-r--r--core/tests/coretests/src/android/provider/DeviceConfigTest.java128
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java86
-rw-r--r--data/etc/services.core.protolog.json105
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java20
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationController.java61
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationRunner.java93
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java10
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt9
-rw-r--r--media/java/android/media/projection/MediaProjection.java11
-rw-r--r--packages/SystemUI/res/layout/communal_host_view.xml11
-rw-r--r--packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml7
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml7
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt9
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt6
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt1
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt19
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt17
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt6
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt42
-rw-r--r--packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/service/CommunalSurfaceViewController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java105
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java129
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java98
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java50
-rw-r--r--services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java37
-rw-r--r--services/core/Android.bp7
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java2
-rw-r--r--services/core/java/com/android/server/am/UserController.java6
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java12
-rw-r--r--services/core/java/com/android/server/audio/RotationHelper.java23
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java2
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsCollection.java3
-rw-r--r--services/core/java/com/android/server/pm/HandlerParams.java148
-rw-r--r--services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java1325
-rw-r--r--services/core/java/com/android/server/pm/InstallParams.java20
-rw-r--r--services/core/java/com/android/server/pm/PackageHandler.java783
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java3054
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java14
-rw-r--r--services/core/java/com/android/server/pm/ScanPartition.java80
-rw-r--r--services/core/java/com/android/server/pm/Settings.java3
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java38
-rw-r--r--services/core/java/com/android/server/pm/VerificationParams.java14
-rw-r--r--services/core/java/com/android/server/pm/permission/Permission.java7
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java25
-rwxr-xr-xservices/core/java/com/android/server/tv/TvInputHardwareManager.java53
-rwxr-xr-xservices/core/java/com/android/server/tv/TvInputManagerService.java5
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java26
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java6
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java68
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java6
-rw-r--r--services/core/java/com/android/server/wm/HighRefreshRateDenylist.java2
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java9
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java16
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java11
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java7
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java3
-rw-r--r--services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java63
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerConstants.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java6
-rw-r--r--services/java/com/android/server/SystemServer.java13
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt12
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackagesBroadcastTest.kt28
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/OWNERS1
-rw-r--r--services/tests/servicestests/Android.bp2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ScanTests.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java3
-rw-r--r--services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java69
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java21
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java40
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java22
-rw-r--r--telecomm/java/android/telecom/Phone.java29
-rw-r--r--tools/aapt/Android.bp1
-rw-r--r--tools/aapt2/Android.bp1
-rwxr-xr-xtools/aosp/aosp_sha.sh1
-rw-r--r--tools/split-select/Android.bp1
118 files changed, 4810 insertions, 3142 deletions
diff --git a/Android.bp b/Android.bp
index b8c060dfff9e..9127966fffc4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -124,7 +124,6 @@ filegroup {
":libbluetooth-binder-aidl",
":libcamera_client_aidl",
":libcamera_client_framework_aidl",
- ":packagemanager_aidl",
":libupdate_engine_aidl",
":resourcemanager_aidl",
":storaged_aidl",
@@ -228,6 +227,7 @@ java_library {
name: "framework-internal-utils",
static_libs: [
"apex_aidl_interface-java",
+ "packagemanager_aidl-java",
"framework-protos",
"updatable-driver-protos",
"ota_metadata_proto_java",
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index e58b479d73ec..6e2742c26d6d 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -88,6 +88,10 @@ import java.util.concurrent.TimeUnit;
public class UserLifecycleTests {
private static final String TAG = UserLifecycleTests.class.getSimpleName();
+ /** Max runtime for each test (including all runs within that test). */
+ // No point exceeding 10 minutes, since device would likely be considered non-responsive anyway.
+ private static final long TIMEOUT_MAX_TEST_TIME_MS = 9 * 60_000;
+
private static final int TIMEOUT_IN_SECOND = 30;
private static final int CHECK_USER_REMOVED_INTERVAL_MS = 200;
@@ -144,7 +148,7 @@ public class UserLifecycleTests {
}
/** Tests creating a new user. */
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void createUser() {
while (mRunner.keepRunning()) {
Log.i(TAG, "Starting timer");
@@ -158,7 +162,7 @@ public class UserLifecycleTests {
}
/** Tests creating and starting a new user. */
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void createAndStartUser() throws RemoteException {
while (mRunner.keepRunning()) {
Log.i(TAG, "Starting timer");
@@ -182,7 +186,7 @@ public class UserLifecycleTests {
* Tests starting an uninitialized user.
* Measures the time until ACTION_USER_STARTED is received.
*/
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void startUser() throws RemoteException {
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
@@ -206,7 +210,7 @@ public class UserLifecycleTests {
* Tests starting & unlocking an uninitialized user.
* Measures the time until unlock listener is triggered and user is unlocked.
*/
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void startAndUnlockUser() {
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
@@ -225,7 +229,7 @@ public class UserLifecycleTests {
}
/** Tests switching to an uninitialized user. */
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void switchUser() throws RemoteException {
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
@@ -245,7 +249,7 @@ public class UserLifecycleTests {
}
/** Tests switching to a previously-started, but no-longer-running, user. */
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void switchUser_stopped() throws RemoteException {
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
@@ -269,7 +273,7 @@ public class UserLifecycleTests {
}
/** Tests switching to an already-created already-running non-owner background user. */
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void switchUser_running() throws RemoteException {
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
@@ -289,7 +293,7 @@ public class UserLifecycleTests {
}
/** Tests stopping a background user. */
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void stopUser() throws RemoteException {
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
@@ -314,7 +318,7 @@ public class UserLifecycleTests {
}
/** Tests reaching LOOKED_BOOT_COMPLETE when switching to uninitialized user. */
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void lockedBootCompleted() throws RemoteException {
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
@@ -337,7 +341,7 @@ public class UserLifecycleTests {
}
/** Tests stopping an ephemeral foreground user. */
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void ephemeralUserStopped() throws RemoteException {
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
@@ -378,7 +382,7 @@ public class UserLifecycleTests {
}
/** Tests creating a new profile. */
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void managedProfileCreate() {
assumeTrue(mHasManagedUserFeature);
@@ -395,7 +399,7 @@ public class UserLifecycleTests {
}
/** Tests starting (unlocking) an uninitialized profile. */
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void managedProfileUnlock() {
assumeTrue(mHasManagedUserFeature);
@@ -415,7 +419,7 @@ public class UserLifecycleTests {
}
/** Tests starting (unlocking) a previously-started, but no-longer-running, profile. */
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void managedProfileUnlock_stopped() throws RemoteException {
assumeTrue(mHasManagedUserFeature);
@@ -440,7 +444,7 @@ public class UserLifecycleTests {
/**
* Tests starting (unlocking) & launching an already-installed app in an uninitialized profile.
*/
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void managedProfileUnlockAndLaunchApp() throws RemoteException {
assumeTrue(mHasManagedUserFeature);
@@ -468,7 +472,7 @@ public class UserLifecycleTests {
* A sort of combination of {@link #managedProfileUnlockAndLaunchApp} and
* {@link #managedProfileUnlock_stopped}}.
*/
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void managedProfileUnlockAndLaunchApp_stopped() throws RemoteException {
assumeTrue(mHasManagedUserFeature);
@@ -495,7 +499,7 @@ public class UserLifecycleTests {
}
/** Tests installing a pre-existing app in an uninitialized profile. */
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void managedProfileInstall() throws RemoteException {
assumeTrue(mHasManagedUserFeature);
@@ -518,7 +522,7 @@ public class UserLifecycleTests {
* Tests creating a new profile, starting (unlocking) it, installing an app,
* and launching that app in it.
*/
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void managedProfileCreateUnlockInstallAndLaunchApp() throws RemoteException {
assumeTrue(mHasManagedUserFeature);
@@ -541,7 +545,7 @@ public class UserLifecycleTests {
}
/** Tests stopping a profile. */
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void managedProfileStopped() throws RemoteException {
assumeTrue(mHasManagedUserFeature);
@@ -566,7 +570,7 @@ public class UserLifecycleTests {
// TODO: This is just a POC. Do this properly and add more.
/** Tests starting (unlocking) a newly-created profile using the user-type-pkg-whitelist. */
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void managedProfileUnlock_usingWhitelist() {
assumeTrue(mHasManagedUserFeature);
final int origMode = getUserTypePackageWhitelistMode();
@@ -592,7 +596,7 @@ public class UserLifecycleTests {
}
}
/** Tests starting (unlocking) a newly-created profile NOT using the user-type-pkg-whitelist. */
- @Test
+ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void managedProfileUnlock_notUsingWhitelist() {
assumeTrue(mHasManagedUserFeature);
final int origMode = getUserTypePackageWhitelistMode();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 61da4a7fecc0..2e22b9231ac3 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1101,17 +1101,18 @@ public final class ActivityThread extends ClientTransactionHandler
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
- CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings,
+ CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial, AutofillOptions autofillOptions,
ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges,
SharedMemory serializedSystemFontMap) {
if (services != null) {
if (false) {
// Test code to make sure the app could see the passed-in services.
- for (String name : services.keySet()) {
- if (services.get(name) == null) {
+ for (Object oname : services.keySet()) {
+ if (services.get(oname) == null) {
continue; // AM just passed in a null service.
}
+ String name = (String) oname;
// See b/79378449 about the following exemption.
switch (name) {
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 2afd98e9d685..d6ff6d3dfc3a 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -77,7 +77,7 @@ oneway interface IApplicationThread {
IInstrumentationWatcher testWatcher, IUiAutomationConnection uiAutomationConnection,
int debugMode, boolean enableBinderTracking, boolean trackAllocation,
boolean restrictedBackupMode, boolean persistent, in Configuration config,
- in CompatibilityInfo compatInfo, in Map<String, IBinder> services,
+ in CompatibilityInfo compatInfo, in Map services,
in Bundle coreSettings, in String buildSerial, in AutofillOptions autofillOptions,
in ContentCaptureOptions contentCaptureOptions, in long[] disabledCompatChanges,
in SharedMemory serializedSystemFontMap);
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 12211485cc07..eee981db49af 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1331,7 +1331,10 @@ public final class BluetoothDevice implements Parcelable, Attributable {
if (alias == null) {
return getName();
}
- return alias;
+ return alias
+ .replace('\t', ' ')
+ .replace('\n', ' ')
+ .replace('\r', ' ');
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index f5a0c431f490..9ff13a472317 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3215,7 +3215,7 @@ public abstract class Context {
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#O}
* or higher are not allowed to start background services from the background.
* See
- * <a href="{@docRoot}/about/versions/oreo/background">
+ * <a href="/about/versions/oreo/background">
* Background Execution Limits</a>
* for more details.
*
@@ -3224,7 +3224,7 @@ public abstract class Context {
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S}
* or higher are not allowed to start foreground services from the background.
* See
- * <a href="{@docRoot}/about/versions/12/behavior-changes-12">
+ * <a href="/about/versions/12/behavior-changes-12">
* Behavior changes: Apps targeting Android 12
* </a>
* for more details.
@@ -3278,7 +3278,7 @@ public abstract class Context {
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S}
* or higher are not allowed to start foreground services from the background.
* See
- * <a href="{@docRoot}/about/versions/12/behavior-changes-12">
+ * <a href="/about/versions/12/behavior-changes-12">
* Behavior changes: Apps targeting Android 12
* </a>
* for more details.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 546abf8ae72e..335e703ddacd 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2739,6 +2739,22 @@ public class Intent implements Parcelable, Cloneable {
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
+ /**
+ * Broadcast Action: One of the suspend conditions have been modified for the packages.
+ * <p>Includes the following extras:
+ * <ul>
+ * <li> {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages which have been modified
+ * <li> {@link #EXTRA_CHANGED_UID_LIST} is the set of uids which have been modified
+ * </ul>
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system. It is only sent to registered receivers.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PACKAGES_SUSPENSION_CHANGED =
+ "android.intent.action.PACKAGES_SUSPENSION_CHANGED";
/**
* Broadcast Action: Distracting packages have been changed.
@@ -4918,6 +4934,12 @@ public class Intent implements Parcelable, Cloneable {
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_CAR_LAUNCHER = "android.intent.category.CAR_LAUNCHER";
/**
+ * Used to indicate that the activity can be used in communal mode.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_COMMUNAL_MODE = "android.intent.category.COMMUNAL_MODE";
+ /**
* Indicates a Leanback settings activity to be displayed in the Leanback launcher.
* @hide
*/
diff --git a/core/java/android/os/ExternalVibration.java b/core/java/android/os/ExternalVibration.java
index 7fd02116814b..0686dd689499 100644
--- a/core/java/android/os/ExternalVibration.java
+++ b/core/java/android/os/ExternalVibration.java
@@ -42,25 +42,38 @@ public class ExternalVibration implements Parcelable {
// boundaries.
@NonNull
private IBinder mToken;
-
public ExternalVibration(int uid, @NonNull String pkg, @NonNull AudioAttributes attrs,
@NonNull IExternalVibrationController controller) {
+ this(uid, pkg, attrs, controller, new Binder());
+ }
+
+ private ExternalVibration(int uid, @NonNull String pkg, @NonNull AudioAttributes attrs,
+ @NonNull IExternalVibrationController controller, @NonNull IBinder token) {
mUid = uid;
mPkg = Preconditions.checkNotNull(pkg);
mAttrs = Preconditions.checkNotNull(attrs);
mController = Preconditions.checkNotNull(controller);
- mToken = new Binder();
+ mToken = Preconditions.checkNotNull(token);
+
+ // IExternalVibrationController is a hidden AIDL interface with implementation provided by
+ // the audio framework to allow mute/unmute control over the external vibration.
+ //
+ // Transactions are locked in audioflinger, and should be blocking to avoid racing
+ // conditions on multiple audio playback.
+ //
+ // They can also be triggered before starting a new external vibration in
+ // IExternalVibratorService, as the ongoing external vibration needs to be muted before the
+ // new one can start, which also requires blocking calls to mute.
+ Binder.allowBlocking(mController.asBinder());
}
private ExternalVibration(Parcel in) {
- mUid = in.readInt();
- mPkg = in.readString();
- mAttrs = readAudioAttributes(in);
- mController = IExternalVibrationController.Stub.asInterface(in.readStrongBinder());
- mToken = in.readStrongBinder();
+ this(in.readInt(), in.readString(), readAudioAttributes(in),
+ IExternalVibrationController.Stub.asInterface(in.readStrongBinder()),
+ in.readStrongBinder());
}
- private AudioAttributes readAudioAttributes(Parcel in) {
+ private static AudioAttributes readAudioAttributes(Parcel in) {
int usage = in.readInt();
int contentType = in.readInt();
int capturePreset = in.readInt();
diff --git a/services/core/java/com/android/server/utils/DeviceConfigInterface.java b/core/java/android/provider/DeviceConfigInterface.java
index ff609031b57c..0a888f40517f 100644
--- a/services/core/java/com/android/server/utils/DeviceConfigInterface.java
+++ b/core/java/android/provider/DeviceConfigInterface.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,57 +14,103 @@
* limitations under the License.
*/
-package com.android.server.utils;
+package android.provider;
+
+import static android.provider.Settings.ResetMode;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.BadConfigException;
+import android.provider.DeviceConfig.Properties;
import java.util.concurrent.Executor;
/**
* Abstraction around {@link DeviceConfig} to allow faking device configuration in tests.
+ *
+ * @hide
*/
public interface DeviceConfigInterface {
+
/**
+ * @hide
* @see DeviceConfig#getProperty
*/
@Nullable
String getProperty(@NonNull String namespace, @NonNull String name);
/**
+ * @hide
+ * @see DeviceConfig#getProperties
+ */
+ @NonNull
+ Properties getProperties(@NonNull String namespace, @NonNull String... names);
+
+ /**
+ * @hide
+ * @see DeviceConfig#setProperty
+ */
+ boolean setProperty(@NonNull String namespace, @NonNull String name, @Nullable String value,
+ boolean makeDefault);
+
+ /**
+ * @hide
+ * @see DeviceConfig#setProperties
+ */
+ boolean setProperties(@NonNull Properties properties) throws BadConfigException;
+
+ /**
+ * @hide
+ * @see DeviceConfig#deleteProperty
+ */
+ boolean deleteProperty(@NonNull String namespace, @NonNull String name);
+
+ /**
+ * @hide
+ * @see DeviceConfig#resetToDefaults
+ */
+ void resetToDefaults(@ResetMode int resetMode, @Nullable String namespace);
+
+ /**
+ * @hide
* @see DeviceConfig#getString
*/
@NonNull
String getString(@NonNull String namespace, @NonNull String name, @NonNull String defaultValue);
/**
+ * @hide
* @see DeviceConfig#getInt
*/
int getInt(@NonNull String namespace, @NonNull String name, int defaultValue);
/**
+ * @hide
* @see DeviceConfig#getLong
*/
long getLong(@NonNull String namespace, @NonNull String name, long defaultValue);
/**
+ * @hide
* @see DeviceConfig#getBoolean
*/
boolean getBoolean(@NonNull String namespace, @NonNull String name, boolean defaultValue);
/**
+ * @hide
* @see DeviceConfig#getFloat
*/
float getFloat(@NonNull String namespace, @NonNull String name, float defaultValue);
/**
+ * @hide
* @see DeviceConfig#addOnPropertiesChangedListener
*/
void addOnPropertiesChangedListener(@NonNull String namespace, @NonNull Executor executor,
@NonNull DeviceConfig.OnPropertiesChangedListener listener);
/**
+ * @hide
* @see DeviceConfig#removeOnPropertiesChangedListener
*/
void removeOnPropertiesChangedListener(
@@ -72,7 +118,10 @@ public interface DeviceConfigInterface {
/**
* Calls through to the real {@link DeviceConfig}.
+ *
+ * @hide
*/
+ @NonNull
DeviceConfigInterface REAL = new DeviceConfigInterface() {
@Override
public String getProperty(String namespace, String name) {
@@ -80,6 +129,36 @@ public interface DeviceConfigInterface {
}
@Override
+ public DeviceConfig.Properties getProperties(@NonNull String namespace,
+ @NonNull String... names) {
+ return DeviceConfig.getProperties(namespace, names);
+ }
+
+ @Override
+ public boolean setProperty(@NonNull String namespace,
+ @NonNull String name,
+ @Nullable String value, boolean makeDefault) {
+ return DeviceConfig.setProperty(namespace, name, value, makeDefault);
+ }
+
+ @Override
+ public boolean setProperties(@NonNull Properties properties)
+ throws BadConfigException {
+ return DeviceConfig.setProperties(properties);
+ }
+
+ @Override
+ public boolean deleteProperty(@NonNull String namespace,
+ @NonNull String name) {
+ return DeviceConfig.deleteProperty(namespace, name);
+ }
+
+ @Override
+ public void resetToDefaults(int resetMode, @Nullable String namespace) {
+ DeviceConfig.resetToDefaults(resetMode, namespace);
+ }
+
+ @Override
public String getString(String namespace, String name, String defaultValue) {
return DeviceConfig.getString(namespace, name, defaultValue);
}
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 1506ee4c2c7a..9d98a3e4b0e1 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -185,6 +185,15 @@ public class InsetsSourceControl implements Parcelable {
return result;
}
+ @Override
+ public String toString() {
+ return "InsetsSourceControl: {"
+ + "type=" + InsetsState.typeToString(mType)
+ + ", mSurfacePosition=" + mSurfacePosition
+ + ", mInsetsHint=" + mInsetsHint
+ + "}";
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix);
pw.print("InsetsSourceControl type="); pw.print(InsetsState.typeToString(mType));
diff --git a/core/java/android/window/ITaskFragmentOrganizerController.aidl b/core/java/android/window/ITaskFragmentOrganizerController.aidl
index 0ca8a864dba5..1ad0452dd837 100644
--- a/core/java/android/window/ITaskFragmentOrganizerController.aidl
+++ b/core/java/android/window/ITaskFragmentOrganizerController.aidl
@@ -16,6 +16,7 @@
package android.window;
+import android.view.RemoteAnimationDefinition;
import android.window.ITaskFragmentOrganizer;
/** @hide */
@@ -30,4 +31,17 @@ interface ITaskFragmentOrganizerController {
* Unregisters a previously registered TaskFragmentOrganizer.
*/
void unregisterOrganizer(in ITaskFragmentOrganizer organizer);
+
+ /**
+ * Registers remote animations per transition type for the organizer. It will override the
+ * animations if the transition only contains windows that belong to the organized
+ * TaskFragments.
+ */
+ void registerRemoteAnimations(in ITaskFragmentOrganizer organizer,
+ in RemoteAnimationDefinition definition);
+
+ /**
+ * Unregisters remote animations per transition type for the organizer.
+ */
+ void unregisterRemoteAnimations(in ITaskFragmentOrganizer organizer);
}
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index f22f0b231ec9..337c5a14e9d3 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -23,6 +23,7 @@ import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.view.RemoteAnimationDefinition;
import java.util.concurrent.Executor;
@@ -90,6 +91,34 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
}
}
+ /**
+ * Registers remote animations per transition type for the organizer. It will override the
+ * animations if the transition only contains windows that belong to the organized
+ * TaskFragments.
+ * @hide
+ */
+ @CallSuper
+ public void registerRemoteAnimations(@NonNull RemoteAnimationDefinition definition) {
+ try {
+ getController().registerRemoteAnimations(mInterface, definition);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unregisters remote animations per transition type for the organizer.
+ * @hide
+ */
+ @CallSuper
+ public void unregisterRemoteAnimations() {
+ try {
+ getController().unregisterRemoteAnimations(mInterface);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** Called when a TaskFragment is created and organized by this organizer. */
public void onTaskFragmentAppeared(
@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {}
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
index 179ac8b1c528..a611d65d6260 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
@@ -39,6 +39,9 @@ import static com.android.internal.util.FrameworkStatsLog.MAGNIFICATION_USAGE_RE
import static com.android.internal.util.FrameworkStatsLog.MAGNIFICATION_USAGE_REPORTED__ACTIVATED_MODE__MAGNIFICATION_FULL_SCREEN;
import static com.android.internal.util.FrameworkStatsLog.MAGNIFICATION_USAGE_REPORTED__ACTIVATED_MODE__MAGNIFICATION_UNKNOWN_MODE;
import static com.android.internal.util.FrameworkStatsLog.MAGNIFICATION_USAGE_REPORTED__ACTIVATED_MODE__MAGNIFICATION_WINDOW;
+import static com.android.internal.util.FrameworkStatsLog.NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_CLICKED;
+import static com.android.internal.util.FrameworkStatsLog.NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_SERVICE_DISABLED;
+import static com.android.internal.util.FrameworkStatsLog.NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_SHOWN;
import android.content.ComponentName;
import android.content.Context;
@@ -50,6 +53,16 @@ import com.android.internal.util.FrameworkStatsLog;
/** Methods for logging accessibility states. */
public final class AccessibilityStatsLogUtils {
+ /** The status represents an accessibility privacy warning has been shown. */
+ public static int ACCESSIBILITY_PRIVACY_WARNING_STATUS_SHOWN =
+ NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_SHOWN;
+ /** The status represents an accessibility privacy warning has been clicked to review. */
+ public static int ACCESSIBILITY_PRIVACY_WARNING_STATUS_CLICKED =
+ NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_CLICKED;
+ /** The status represents an accessibility privacy warning service has been disabled. */
+ public static int ACCESSIBILITY_PRIVACY_WARNING_STATUS_SERVICE_DISABLED =
+ NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_SERVICE_DISABLED;
+
private static final int UNKNOWN_STATUS =
ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__UNKNOWN;
@@ -154,6 +167,23 @@ public final class AccessibilityStatsLogUtils {
convertToLoggingMagnificationMode(mode));
}
+ /**
+ * Logs the warning status of the non-a11yTool service. Calls this when the warning status is
+ * changed.
+ *
+ * @param packageName The package name of the non-a11yTool service
+ * @param status The warning status of the non-a11yTool service, it should be one of
+ * {@code ACCESSIBILITY_PRIVACY_WARNING_STATUS_SHOWN},{@code
+ * ACCESSIBILITY_PRIVACY_WARNING_STATUS_CLICKED} and {@code
+ * ACCESSIBILITY_PRIVACY_WARNING_STATUS_SERVICE_DISABLED}
+ * @param durationMillis The duration in milliseconds between current and previous status
+ */
+ public static void logNonA11yToolServiceWarningReported(String packageName, int status,
+ long durationMillis) {
+ FrameworkStatsLog.write(FrameworkStatsLog.NON_A11Y_TOOL_SERVICE_WARNING_REPORT,
+ packageName, status, durationMillis);
+ }
+
private static boolean isAccessibilityFloatingMenuEnabled(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, /* def= */ -1)
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index 84354d90b5f3..ec224e50eb8d 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -72,17 +72,19 @@ public class SuspendedAppActivity extends AlertActivity
private Resources mSuspendingAppResources;
private SuspendDialogInfo mSuppliedDialogInfo;
private Bundle mOptions;
- private BroadcastReceiver mUnsuspendReceiver = new BroadcastReceiver() {
+ private BroadcastReceiver mSuspendModifiedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_PACKAGES_UNSUSPENDED.equals(intent.getAction())) {
- final String[] unsuspended = intent.getStringArrayExtra(
+ if (Intent.ACTION_PACKAGES_SUSPENSION_CHANGED.equals(intent.getAction())) {
+ // Suspension conditions were modified, dismiss any related visible dialogs.
+ final String[] modified = intent.getStringArrayExtra(
Intent.EXTRA_CHANGED_PACKAGE_LIST);
- if (ArrayUtils.contains(unsuspended, mSuspendedPackage)) {
+ if (ArrayUtils.contains(modified, mSuspendedPackage)) {
if (!isFinishing()) {
- Slog.w(TAG, "Package " + mSuspendedPackage
- + " got unsuspended while the dialog was visible. Finishing.");
+ Slog.w(TAG, "Package " + mSuspendedPackage + " has modified"
+ + " suspension conditions while dialog was visible. Finishing.");
SuspendedAppActivity.this.finish();
+ // TODO (b/198201994): reload the suspend dialog to show most relevant info
}
}
}
@@ -245,15 +247,16 @@ public class SuspendedAppActivity extends AlertActivity
setupAlert();
- final IntentFilter unsuspendFilter = new IntentFilter(Intent.ACTION_PACKAGES_UNSUSPENDED);
- registerReceiverAsUser(mUnsuspendReceiver, UserHandle.of(mUserId), unsuspendFilter, null,
- null);
+ final IntentFilter suspendModifiedFilter =
+ new IntentFilter(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED);
+ registerReceiverAsUser(mSuspendModifiedReceiver, UserHandle.of(mUserId),
+ suspendModifiedFilter, null, null);
}
@Override
protected void onDestroy() {
super.onDestroy();
- unregisterReceiver(mUnsuspendReceiver);
+ unregisterReceiver(mSuspendModifiedReceiver);
}
private void requestDismissKeyguardIfNeeded(CharSequence dismissMessage) {
diff --git a/core/java/com/android/internal/inputmethod/IIntResultCallback.aidl b/core/java/com/android/internal/inputmethod/IIntResultCallback.aidl
deleted file mode 100644
index ceda66c29a98..000000000000
--- a/core/java/com/android/internal/inputmethod/IIntResultCallback.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-import com.android.internal.inputmethod.ThrowableHolder;
-
-oneway interface IIntResultCallback {
- void onResult(int result);
- void onError(in ThrowableHolder exception);
-}
diff --git a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
index 2d0b3f9e5025..74211fb974df 100644
--- a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
@@ -43,6 +43,7 @@ import com.android.internal.infra.AndroidFuture;
import com.android.internal.view.IInputContext;
import java.lang.ref.WeakReference;
+import java.util.function.Supplier;
/**
* Takes care of remote method invocations of {@link InputConnection} in the IME client side.
@@ -222,9 +223,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
@Override
public void getTextAfterCursor(int length, int flags,
AndroidFuture future /* T=CharSequence */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<CharSequence> typedFuture = future;
- dispatch(() -> {
+ dispatch(future, () -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextAfterCursor");
try {
final InputConnection ic = getInputConnection();
@@ -241,7 +240,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
ImeTracing.getInstance().triggerClientDump(
TAG + "#getTextAfterCursor", mParentInputMethodManager, icProto);
}
- typedFuture.complete(result);
+ return result;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -251,9 +250,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
@Override
public void getTextBeforeCursor(int length, int flags,
AndroidFuture future /* T=CharSequence */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<CharSequence> typedFuture = future;
- dispatch(() -> {
+ dispatch(future, () -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextBeforeCursor");
try {
final InputConnection ic = getInputConnection();
@@ -270,7 +267,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
ImeTracing.getInstance().triggerClientDump(
TAG + "#getTextBeforeCursor", mParentInputMethodManager, icProto);
}
- typedFuture.complete(result);
+ return result;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -279,9 +276,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
@Override
public void getSelectedText(int flags, AndroidFuture future /* T=CharSequence */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<CharSequence> typedFuture = future;
- dispatch(() -> {
+ dispatch(future, () -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSelectedText");
try {
final InputConnection ic = getInputConnection();
@@ -298,7 +293,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
ImeTracing.getInstance().triggerClientDump(
TAG + "#getSelectedText", mParentInputMethodManager, icProto);
}
- typedFuture.complete(result);
+ return result;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -308,9 +303,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
@Override
public void getSurroundingText(int beforeLength, int afterLength, int flags,
AndroidFuture future /* T=SurroundingText */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<SurroundingText> typedFuture = future;
- dispatch(() -> {
+ dispatch(future, () -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSurroundingText");
try {
final InputConnection ic = getInputConnection();
@@ -327,7 +320,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
ImeTracing.getInstance().triggerClientDump(
TAG + "#getSurroundingText", mParentInputMethodManager, icProto);
}
- typedFuture.complete(result);
+ return result;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -336,9 +329,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
@Override
public void getCursorCapsMode(int reqModes, AndroidFuture future /* T=Integer */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<Integer> typedFuture = future;
- dispatch(() -> {
+ dispatch(future, () -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getCursorCapsMode");
try {
final InputConnection ic = getInputConnection();
@@ -355,7 +346,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
ImeTracing.getInstance().triggerClientDump(
TAG + "#getCursorCapsMode", mParentInputMethodManager, icProto);
}
- typedFuture.complete(result);
+ return result;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -365,9 +356,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
@Override
public void getExtractedText(ExtractedTextRequest request, int flags,
AndroidFuture future /* T=ExtractedText */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<ExtractedText> typedFuture = future;
- dispatch(() -> {
+ dispatch(future, () -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getExtractedText");
try {
final InputConnection ic = getInputConnection();
@@ -384,7 +373,7 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
ImeTracing.getInstance().triggerClientDump(
TAG + "#getExtractedText", mParentInputMethodManager, icProto);
}
- typedFuture.complete(result);
+ return result;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -695,20 +684,15 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
@Override
public void requestCursorUpdates(int cursorUpdateMode, AndroidFuture future /* T=Boolean */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<Boolean> typedFuture = future;
- dispatch(() -> {
+ dispatch(future, () -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#requestCursorUpdates");
try {
final InputConnection ic = getInputConnection();
- final boolean result;
if (ic == null || !isActive()) {
Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
- result = false;
- } else {
- result = ic.requestCursorUpdates(cursorUpdateMode);
+ return false;
}
- typedFuture.complete(result);
+ return ic.requestCursorUpdates(cursorUpdateMode);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -718,26 +702,19 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
@Override
public void commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts,
AndroidFuture future /* T=Boolean */) {
- @SuppressWarnings("unchecked")
- final AndroidFuture<Boolean> typedFuture = future;
- dispatch(() -> {
+ dispatch(future, () -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitContent");
try {
final InputConnection ic = getInputConnection();
- final boolean result;
if (ic == null || !isActive()) {
Log.w(TAG, "commitContent on inactive InputConnection");
- result = false;
- } else {
- if (inputContentInfo == null || !inputContentInfo.validate()) {
- Log.w(TAG, "commitContent with invalid inputContentInfo="
- + inputContentInfo);
- result = false;
- } else {
- result = ic.commitContent(inputContentInfo, flags, opts);
- }
+ return false;
+ }
+ if (inputContentInfo == null || !inputContentInfo.validate()) {
+ Log.w(TAG, "commitContent with invalid inputContentInfo=" + inputContentInfo);
+ return false;
}
- typedFuture.complete(result);
+ return ic.commitContent(inputContentInfo, flags, opts);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -771,4 +748,10 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
mH.post(runnable);
}
+
+ private <T> void dispatch(@NonNull AndroidFuture untypedFuture, @NonNull Supplier<T> supplier) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<T> future = untypedFuture;
+ dispatch(() -> future.complete(supplier.get()));
+ }
}
diff --git a/core/java/com/android/internal/inputmethod/ThrowableHolder.aidl b/core/java/com/android/internal/inputmethod/ThrowableHolder.aidl
deleted file mode 100644
index ed1129345061..000000000000
--- a/core/java/com/android/internal/inputmethod/ThrowableHolder.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-parcelable ThrowableHolder; \ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/ThrowableHolder.java b/core/java/com/android/internal/inputmethod/ThrowableHolder.java
deleted file mode 100644
index b6f449864e54..000000000000
--- a/core/java/com/android/internal/inputmethod/ThrowableHolder.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-import android.annotation.AnyThread;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * A {@link Parcelable} helper class to encapsulate the exception information.
- */
-public final class ThrowableHolder implements Parcelable {
-
- @Nullable
- private final String mMessage;
-
- ThrowableHolder(@NonNull Throwable throwable) {
- mMessage = throwable.getMessage();
- }
-
- ThrowableHolder(Parcel source) {
- mMessage = source.readString();
- }
-
- /**
- * Returns a {@link ThrowableHolder} with given {@link Throwable}.
- */
- @NonNull
- @AnyThread
- public static ThrowableHolder of(@NonNull Throwable throwable) {
- return new ThrowableHolder(throwable);
- }
-
- /**
- * Gets the message in this {@link ThrowableHolder}.
- */
- @Nullable
- @AnyThread
- String getMessage() {
- return mMessage;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- /**
- * Used to package this object into a {@link Parcel}.
- *
- * @param dest The {@link Parcel} to be written.
- * @param flags The flags used for parceling.
- */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mMessage);
- }
-
- /**
- * Used to make this class parcelable.
- */
- public static final Parcelable.Creator<ThrowableHolder> CREATOR =
- new Parcelable.Creator<ThrowableHolder>() {
-
- @Override
- public ThrowableHolder createFromParcel(Parcel source) {
- return new ThrowableHolder(source);
- }
-
- @Override
- public ThrowableHolder[] newArray(int size) {
- return new ThrowableHolder[size];
- }
- };
-}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 40430605f186..719dc5396c77 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -661,6 +661,10 @@ public class BatteryStatsImpl extends BatteryStats {
* Mapping isolated uids to the actual owning app uid.
*/
final SparseIntArray mIsolatedUids = new SparseIntArray();
+ /**
+ * Internal reference count of isolated uids.
+ */
+ final SparseIntArray mIsolatedUidRefCounts = new SparseIntArray();
/**
* The statistics we have collected organized by uids.
@@ -3855,6 +3859,7 @@ public class BatteryStatsImpl extends BatteryStats {
public void addIsolatedUidLocked(int isolatedUid, int appUid,
long elapsedRealtimeMs, long uptimeMs) {
mIsolatedUids.put(isolatedUid, appUid);
+ mIsolatedUidRefCounts.put(isolatedUid, 1);
final Uid u = getUidStatsLocked(appUid, elapsedRealtimeMs, uptimeMs);
u.addIsolatedUid(isolatedUid);
}
@@ -3873,19 +3878,51 @@ public class BatteryStatsImpl extends BatteryStats {
}
/**
- * This should only be called after the cpu times have been read.
+ * Isolated uid should only be removed after all wakelocks associated with the uid are stopped
+ * and the cpu time-in-state has been read one last time for the uid.
+ *
* @see #scheduleRemoveIsolatedUidLocked(int, int)
+ *
+ * @return true if the isolated uid is actually removed.
*/
@GuardedBy("this")
- public void removeIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs, long uptimeMs) {
+ public boolean maybeRemoveIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs,
+ long uptimeMs) {
+ final int refCount = mIsolatedUidRefCounts.get(isolatedUid, 0) - 1;
+ if (refCount > 0) {
+ // Isolated uid is still being tracked
+ mIsolatedUidRefCounts.put(isolatedUid, refCount);
+ return false;
+ }
+
final int idx = mIsolatedUids.indexOfKey(isolatedUid);
if (idx >= 0) {
final int ownerUid = mIsolatedUids.valueAt(idx);
final Uid u = getUidStatsLocked(ownerUid, elapsedRealtimeMs, uptimeMs);
u.removeIsolatedUid(isolatedUid);
mIsolatedUids.removeAt(idx);
+ mIsolatedUidRefCounts.delete(isolatedUid);
+ } else {
+ Slog.w(TAG, "Attempted to remove untracked isolated uid (" + isolatedUid + ")");
}
mPendingRemovedUids.add(new UidToRemove(isolatedUid, elapsedRealtimeMs));
+
+ return true;
+ }
+
+ /**
+ * Increment the ref count for an isolated uid.
+ * call #maybeRemoveIsolatedUidLocked to decrement.
+ */
+ public void incrementIsolatedUidRefCount(int uid) {
+ final int refCount = mIsolatedUidRefCounts.get(uid, 0);
+ if (refCount <= 0) {
+ // Uid is not mapped or referenced
+ Slog.w(TAG,
+ "Attempted to increment ref counted of untracked isolated uid (" + uid + ")");
+ return;
+ }
+ mIsolatedUidRefCounts.put(uid, refCount + 1);
}
public int mapUid(int uid) {
@@ -4245,7 +4282,7 @@ public class BatteryStatsImpl extends BatteryStats {
public void noteStartWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
int type, boolean unimportantForLogging, long elapsedRealtimeMs, long uptimeMs) {
- uid = mapUid(uid);
+ final int mappedUid = mapUid(uid);
if (type == WAKE_TYPE_PARTIAL) {
// Only care about partial wake locks, since full wake locks
// will be canceled when the user puts the screen to sleep.
@@ -4255,9 +4292,9 @@ public class BatteryStatsImpl extends BatteryStats {
}
if (mRecordAllHistory) {
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
- uid, 0)) {
+ mappedUid, 0)) {
addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
- HistoryItem.EVENT_WAKE_LOCK_START, historyName, uid);
+ HistoryItem.EVENT_WAKE_LOCK_START, historyName, mappedUid);
}
}
if (mWakeLockNesting == 0) {
@@ -4266,7 +4303,7 @@ public class BatteryStatsImpl extends BatteryStats {
+ Integer.toHexString(mHistoryCur.states));
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
- mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
+ mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid;
mWakeLockImportant = !unimportantForLogging;
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
} else if (!mWakeLockImportant && !unimportantForLogging
@@ -4276,14 +4313,19 @@ public class BatteryStatsImpl extends BatteryStats {
mHistoryLastWritten.wakelockTag = null;
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
- mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
+ mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid;
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
}
mWakeLockImportant = true;
}
mWakeLockNesting++;
}
- if (uid >= 0) {
+ if (mappedUid >= 0) {
+ if (mappedUid != uid) {
+ // Prevent the isolated uid mapping from being removed while the wakelock is
+ // being held.
+ incrementIsolatedUidRefCount(uid);
+ }
if (mOnBatteryScreenOffTimeBase.isRunning()) {
// We only update the cpu time when a wake lock is acquired if the screen is off.
// If the screen is on, we don't distribute the power amongst partial wakelocks.
@@ -4293,7 +4335,7 @@ public class BatteryStatsImpl extends BatteryStats {
requestWakelockCpuUpdate();
}
- getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+ getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs)
.noteStartWakeLocked(pid, name, type, elapsedRealtimeMs);
if (wc != null) {
@@ -4301,8 +4343,8 @@ public class BatteryStatsImpl extends BatteryStats {
wc.getTags(), getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
} else {
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid,
- null, getPowerManagerWakeLockLevel(type), name,
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
+ mappedUid, null, getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
}
}
@@ -4316,7 +4358,7 @@ public class BatteryStatsImpl extends BatteryStats {
public void noteStopWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
int type, long elapsedRealtimeMs, long uptimeMs) {
- uid = mapUid(uid);
+ final int mappedUid = mapUid(uid);
if (type == WAKE_TYPE_PARTIAL) {
mWakeLockNesting--;
if (mRecordAllHistory) {
@@ -4324,9 +4366,9 @@ public class BatteryStatsImpl extends BatteryStats {
historyName = name;
}
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName,
- uid, 0)) {
+ mappedUid, 0)) {
addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
- HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, uid);
+ HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, mappedUid);
}
}
if (mWakeLockNesting == 0) {
@@ -4338,7 +4380,7 @@ public class BatteryStatsImpl extends BatteryStats {
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
}
}
- if (uid >= 0) {
+ if (mappedUid >= 0) {
if (mOnBatteryScreenOffTimeBase.isRunning()) {
if (DEBUG_ENERGY_CPU) {
Slog.d(TAG, "Updating cpu time because of -wake_lock");
@@ -4346,17 +4388,22 @@ public class BatteryStatsImpl extends BatteryStats {
requestWakelockCpuUpdate();
}
- getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+ getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs)
.noteStopWakeLocked(pid, name, type, elapsedRealtimeMs);
if (wc != null) {
FrameworkStatsLog.write(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(),
wc.getTags(), getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
} else {
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid,
- null, getPowerManagerWakeLockLevel(type), name,
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
+ mappedUid, null, getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
}
+
+ if (mappedUid != uid) {
+ // Decrement the ref count for the isolated uid and delete the mapping if uneeded.
+ maybeRemoveIsolatedUidLocked(uid, elapsedRealtimeMs, uptimeMs);
+ }
}
}
@@ -16769,6 +16816,15 @@ public class BatteryStatsImpl extends BatteryStats {
pw.print("UIDs removed since the later of device start or stats reset: ");
pw.println(mNumUidsRemoved);
+ pw.println("Currently mapped isolated uids:");
+ final int numIsolatedUids = mIsolatedUids.size();
+ for (int i = 0; i < numIsolatedUids; i++) {
+ final int isolatedUid = mIsolatedUids.keyAt(i);
+ final int ownerUid = mIsolatedUids.valueAt(i);
+ final int refCount = mIsolatedUidRefCounts.get(isolatedUid);
+ pw.println(" " + isolatedUid + "->" + ownerUid + " (ref count = " + refCount + ")");
+ }
+
pw.println();
dumpConstantsLocked(pw);
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index ce3efd35ee48..0f153bcdf1d4 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -80,6 +80,8 @@ public enum ProtoLogGroup implements IProtoLogGroup {
Consts.TAG_WM),
WM_DEBUG_WINDOW_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
Consts.TAG_WM),
+ WM_DEBUG_WINDOW_INSETS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
TEST_GROUP(true, true, false, "WindowManagerProtoLogTest");
private final boolean mEnabled;
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7fe4b65990f9..8813c43df7e0 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -660,6 +660,9 @@
<!-- Indicates whether to enable an animation when unfolding a device or not -->
<bool name="config_unfoldTransitionEnabled">false</bool>
+ <!-- Indicates whether to enable hinge angle sensor when using unfold animation -->
+ <bool name="config_unfoldTransitionHingeAngle">false</bool>
+
<!-- Indicates that the device supports having more than one internal display on at the same
time. Only applicable to devices with more than one internal display. If this option is
set to false, DisplayManager will make additional effort to ensure no more than 1 internal
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d2c6f7880cb9..d419f8008108 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4557,7 +4557,7 @@
<string name="accessibility_shortcut_multiple_service_warning">Holding down both volume keys for a few seconds turns on accessibility features. This may change how your device works.\n\nCurrent features:\n<xliff:g id="service" example="TalkBack">%1$s</xliff:g>\nYou can change selected features in Settings > Accessibility.</string>
<!-- Used in multiple service warning to list current features. [CHAR LIMIT=none] -->
- <string name="accessibility_shortcut_multiple_service_list">\t• <xliff:g id="service" example="TalkBack">%1$s</xliff:g>\n</string>
+ <string name="accessibility_shortcut_multiple_service_list">\u0020• <xliff:g id="service" example="TalkBack">%1$s</xliff:g>\n</string>
<!-- Dialog title for dialog shown when this accessibility shortcut is activated, and we want to confirm that the user understands what's going to happen. [CHAR LIMIT=none] -->
<string name="accessibility_shortcut_single_service_warning_title">Turn on <xliff:g id="service" example="TalkBack">%1$s</xliff:g> shortcut?</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 527b92895aa5..b2f7e8227e7d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3844,6 +3844,7 @@
<java-symbol type="string" name="config_foldedArea" />
<java-symbol type="bool" name="config_supportsConcurrentInternalDisplays" />
<java-symbol type="bool" name="config_unfoldTransitionEnabled" />
+ <java-symbol type="bool" name="config_unfoldTransitionHingeAngle" />
<java-symbol type="array" name="config_perDeviceStateRotationLockDefaults" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 37d059a575f0..69d2c74100e0 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -274,6 +274,6 @@
<shortcode country="yt" pattern="\\d{1,5}" free="38600,36300,36303,959" />
<!-- South Africa -->
- <shortcode country="za" pattern="\d{1,5}" free="44136|30791|36056" />
+ <shortcode country="za" pattern="\\d{1,5}" free="44136|30791|36056" />
</shortcodes>
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index fd7753b66a46..5b3be58ae0de 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -22,6 +22,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.testng.Assert.assertThrows;
+import android.app.ActivityThread;
import android.content.ContentResolver;
import android.os.Bundle;
import android.platform.test.annotations.Presubmit;
@@ -35,6 +36,12 @@ import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
/** Tests that ensure appropriate settings are backed up. */
@Presubmit
@RunWith(AndroidJUnit4.class)
@@ -701,66 +708,67 @@ public class DeviceConfigTest {
assertThat(result.getString(KEY4, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE);
}
- // TODO(mpape): resolve b/142727848 and re-enable listener tests
-// @Test
-// public void onPropertiesChangedListener_setPropertyCallback() throws InterruptedException {
-// final CountDownLatch countDownLatch = new CountDownLatch(1);
-//
-// DeviceConfig.OnPropertiesChangedListener changeListener = (properties) -> {
-// assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
-// assertThat(properties.getKeyset()).contains(KEY);
-// assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE);
-// countDownLatch.countDown();
-// };
-//
-// try {
-// DeviceConfig.addOnPropertiesChangedListener(NAMESPACE,
-// ActivityThread.currentApplication().getMainExecutor(), changeListener);
-// DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false);
-// assertThat(countDownLatch.await(
-// WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
-// } catch (InterruptedException e) {
-// Assert.fail(e.getMessage());
-// } finally {
-// DeviceConfig.removeOnPropertiesChangedListener(changeListener);
-// }
-// }
-//
-// @Test
-// public void onPropertiesChangedListener_setPropertiesCallback() throws InterruptedException {
-// final CountDownLatch countDownLatch = new CountDownLatch(1);
-// DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false);
-// DeviceConfig.setProperty(NAMESPACE, KEY2, VALUE2, false);
-//
-// Map<String, String> keyValues = new HashMap<>(2);
-// keyValues.put(KEY, VALUE2);
-// keyValues.put(KEY3, VALUE3);
-// Properties setProperties = new Properties(NAMESPACE, keyValues);
-//
-// DeviceConfig.OnPropertiesChangedListener changeListener = (properties) -> {
-// assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
-// assertThat(properties.getKeyset()).containsExactly(KEY, KEY2, KEY3);
-// // KEY updated from VALUE to VALUE2
-// assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE2);
-// // KEY2 deleted (returns default_value)
-// assertThat(properties.getString(KEY2, "default_value")).isEqualTo("default_value");
-// //KEY3 added with VALUE3
-// assertThat(properties.getString(KEY3, "default_value")).isEqualTo(VALUE3);
-// countDownLatch.countDown();
-// };
-//
-// try {
-// DeviceConfig.addOnPropertiesChangedListener(NAMESPACE,
-// ActivityThread.currentApplication().getMainExecutor(), changeListener);
-// DeviceConfig.setProperties(setProperties);
-// assertThat(countDownLatch.await(
-// WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
-// } catch (InterruptedException e) {
-// Assert.fail(e.getMessage());
-// } finally {
-// DeviceConfig.removeOnPropertiesChangedListener(changeListener);
-// }
-// }
+ @Test
+ public void onPropertiesChangedListener_setPropertyCallback() throws InterruptedException {
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+
+ DeviceConfig.OnPropertiesChangedListener changeListener = (properties) -> {
+ assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
+ assertThat(properties.getKeyset()).contains(KEY);
+ assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE);
+ countDownLatch.countDown();
+ };
+
+ try {
+ DeviceConfig.addOnPropertiesChangedListener(NAMESPACE,
+ Objects.requireNonNull(ActivityThread.currentApplication()).getMainExecutor(),
+ changeListener);
+ DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false);
+ assertThat(countDownLatch.await(
+ WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
+ } catch (InterruptedException e) {
+ Assert.fail(e.getMessage());
+ } finally {
+ DeviceConfig.removeOnPropertiesChangedListener(changeListener);
+ }
+ }
+
+ @Test
+ public void onPropertiesChangedListener_setPropertiesCallback() {
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false);
+ DeviceConfig.setProperty(NAMESPACE, KEY2, VALUE2, false);
+
+ Map<String, String> keyValues = new HashMap<>(2);
+ keyValues.put(KEY, VALUE2);
+ keyValues.put(KEY3, VALUE3);
+ Properties setProperties = new Properties(NAMESPACE, keyValues);
+
+ DeviceConfig.OnPropertiesChangedListener changeListener = (properties) -> {
+ assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
+ assertThat(properties.getKeyset()).containsExactly(KEY, KEY2, KEY3);
+ // KEY updated from VALUE to VALUE2
+ assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE2);
+ // KEY2 deleted (returns default_value)
+ assertThat(properties.getString(KEY2, "default_value")).isEqualTo("default_value");
+ //KEY3 added with VALUE3
+ assertThat(properties.getString(KEY3, "default_value")).isEqualTo(VALUE3);
+ countDownLatch.countDown();
+ };
+
+ try {
+ DeviceConfig.addOnPropertiesChangedListener(NAMESPACE,
+ Objects.requireNonNull(ActivityThread.currentApplication()).getMainExecutor(),
+ changeListener);
+ DeviceConfig.setProperties(setProperties);
+ assertThat(countDownLatch.await(
+ WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
+ } catch (InterruptedException | DeviceConfig.BadConfigException e) {
+ Assert.fail(e.getMessage());
+ } finally {
+ DeviceConfig.removeOnPropertiesChangedListener(changeListener);
+ }
+ }
@Test
public void syncDisabling() throws Exception {
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index a43d32d00bb6..e8e43300ee01 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -23,6 +23,8 @@ import android.app.ActivityManager;
import android.os.BatteryStats;
import android.os.BatteryStats.HistoryItem;
import android.os.BatteryStats.Uid.Sensor;
+import android.os.Process;
+import android.os.UserHandle;
import android.os.WorkSource;
import android.util.SparseLongArray;
import android.view.Display;
@@ -53,6 +55,8 @@ import java.util.Map;
public class BatteryStatsNoteTest extends TestCase {
private static final int UID = 10500;
+ private static final int ISOLATED_APP_ID = Process.FIRST_ISOLATED_UID + 23;
+ private static final int ISOLATED_UID = UserHandle.getUid(0, ISOLATED_APP_ID);
private static final WorkSource WS = new WorkSource(UID);
/**
@@ -114,6 +118,88 @@ public class BatteryStatsNoteTest extends TestCase {
assertEquals(120_000, bgTime);
}
+ /**
+ * Test BatteryStatsImpl.Uid.noteStartWakeLocked for an isolated uid.
+ */
+ @SmallTest
+ public void testNoteStartWakeLocked_isolatedUid() throws Exception {
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+
+ int pid = 10;
+ String name = "name";
+ String historyName = "historyName";
+
+ WorkSource.WorkChain isolatedWorkChain = new WorkSource.WorkChain();
+ isolatedWorkChain.addNode(ISOLATED_UID, name);
+
+ // Map ISOLATED_UID to UID.
+ bi.addIsolatedUidLocked(ISOLATED_UID, UID);
+
+ bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+ bi.noteStartWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName,
+ WAKE_TYPE_PARTIAL, false);
+
+ clocks.realtime = clocks.uptime = 100;
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+
+ clocks.realtime = clocks.uptime = 220;
+ bi.noteStopWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName,
+ WAKE_TYPE_PARTIAL);
+
+ // ISOLATED_UID wakelock time should be attributed to UID.
+ BatteryStats.Timer aggregTimer = bi.getUidStats().get(UID)
+ .getAggregatedPartialWakelockTimer();
+ long actualTime = aggregTimer.getTotalTimeLocked(300_000, STATS_SINCE_CHARGED);
+ long bgTime = aggregTimer.getSubTimer().getTotalTimeLocked(300_000, STATS_SINCE_CHARGED);
+ assertEquals(220_000, actualTime);
+ assertEquals(120_000, bgTime);
+ }
+
+ /**
+ * Test BatteryStatsImpl.Uid.noteStartWakeLocked for an isolated uid, with a race where the
+ * isolated uid is removed from batterystats before the wakelock has been stopped.
+ */
+ @SmallTest
+ public void testNoteStartWakeLocked_isolatedUidRace() throws Exception {
+ final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+
+ int pid = 10;
+ String name = "name";
+ String historyName = "historyName";
+
+ WorkSource.WorkChain isolatedWorkChain = new WorkSource.WorkChain();
+ isolatedWorkChain.addNode(ISOLATED_UID, name);
+
+ // Map ISOLATED_UID to UID.
+ bi.addIsolatedUidLocked(ISOLATED_UID, UID);
+
+ bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+ bi.noteStartWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName,
+ WAKE_TYPE_PARTIAL, false);
+
+ clocks.realtime = clocks.uptime = 100;
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+
+ clocks.realtime = clocks.uptime = 150;
+ bi.maybeRemoveIsolatedUidLocked(ISOLATED_UID, clocks.realtime, clocks.uptime);
+
+ clocks.realtime = clocks.uptime = 220;
+ bi.noteStopWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName,
+ WAKE_TYPE_PARTIAL);
+
+ // ISOLATED_UID wakelock time should be attributed to UID.
+ BatteryStats.Timer aggregTimer = bi.getUidStats().get(UID)
+ .getAggregatedPartialWakelockTimer();
+ long actualTime = aggregTimer.getTotalTimeLocked(300_000, STATS_SINCE_CHARGED);
+ long bgTime = aggregTimer.getSubTimer().getTotalTimeLocked(300_000, STATS_SINCE_CHARGED);
+ assertEquals(220_000, actualTime);
+ assertEquals(120_000, bgTime);
+ }
+
/**
* Test BatteryStatsImpl.noteUidProcessStateLocked.
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index b49b289d44c0..6a93761454f1 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -571,6 +571,12 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityStarter.java"
},
+ "-1483435730": {
+ "message": "InsetsSource setWin %s for type %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_WINDOW_INSETS",
+ "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+ },
"-1480772131": {
"message": "No app or window is requesting an orientation, return %d for display id=%d",
"level": "VERBOSE",
@@ -673,6 +679,12 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
},
+ "-1394745488": {
+ "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_WINDOW_INSETS",
+ "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+ },
"-1391944764": {
"message": "SURFACE DESTROY: %s. %s",
"level": "INFO",
@@ -721,12 +733,6 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "-1312861660": {
- "message": "notifyInsetsControlChanged for %s ",
- "level": "DEBUG",
- "group": "WM_DEBUG_IME",
- "at": "com\/android\/server\/wm\/WindowState.java"
- },
"-1311436264": {
"message": "Unregister task fragment organizer=%s uid=%d pid=%d",
"level": "VERBOSE",
@@ -835,6 +841,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/TaskFragment.java"
},
+ "-1185473319": {
+ "message": "ControlAdapter startAnimation mSource: %s controlTarget: %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_WINDOW_INSETS",
+ "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+ },
"-1176488860": {
"message": "SURFACE isSecure=%b: %s",
"level": "INFO",
@@ -1249,6 +1261,12 @@
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/Transition.java"
},
+ "-702650156": {
+ "message": "Override with TaskFragment remote animation for transit=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_APP_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/AppTransitionController.java"
+ },
"-701167286": {
"message": "applyAnimation: transit=%s, enter=%b, wc=%s",
"level": "VERBOSE",
@@ -1531,12 +1549,6 @@
"group": "WM_DEBUG_TASKS",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
- "-395922585": {
- "message": "InsetsSource setWin %s",
- "level": "DEBUG",
- "group": "WM_DEBUG_IME",
- "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
- },
"-393505149": {
"message": "unable to update pointer icon",
"level": "WARN",
@@ -1741,12 +1753,6 @@
"group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-112805366": {
- "message": "InsetsSource updateVisibility serverVisible: %s clientVisible: %s",
- "level": "DEBUG",
- "group": "WM_DEBUG_IME",
- "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
- },
"-108977760": {
"message": "Sandbox max bounds for uid %s to bounds %s. config to never sandbox = %s, config to always sandbox = %s, letterboxing from mismatch with parent bounds = %s, has mCompatDisplayInsets = %s, should create compatDisplayInsets = %s",
"level": "DEBUG",
@@ -1789,6 +1795,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/TaskFragment.java"
},
+ "-70719599": {
+ "message": "Unregister remote animations for organizer=%s uid=%d pid=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+ },
"-55185509": {
"message": "setFocusedTask: taskId=%d touchedActivity=%s",
"level": "DEBUG",
@@ -1849,12 +1861,6 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimationController.java"
},
- "29780972": {
- "message": "InsetsSource Control %s for target %s",
- "level": "DEBUG",
- "group": "WM_DEBUG_IME",
- "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
- },
"35398067": {
"message": "goodToGo(): onAnimationStart, transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
"level": "DEBUG",
@@ -1897,24 +1903,12 @@
"group": "WM_DEBUG_TASKS",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
- "73987756": {
- "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
- "level": "INFO",
- "group": "WM_DEBUG_IME",
- "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
- },
"74885950": {
"message": "Waiting for top state to be released by %s",
"level": "VERBOSE",
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
},
- "75707221": {
- "message": "ControlAdapter startAnimation mSource: %s controlTarget: %s",
- "level": "INFO",
- "group": "WM_DEBUG_IME",
- "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
- },
"83950285": {
"message": "removeAnimation(%d)",
"level": "DEBUG",
@@ -2287,6 +2281,12 @@
"group": "WM_SHOW_SURFACE_ALLOC",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
+ "416924848": {
+ "message": "InsetsSource Control %s for target %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_WINDOW_INSETS",
+ "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+ },
"417311568": {
"message": "onResize: Resizing %s",
"level": "DEBUG",
@@ -2803,6 +2803,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1030898920": {
+ "message": "notifyInsetsControlChanged for %s ",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_WINDOW_INSETS",
+ "at": "com\/android\/server\/wm\/WindowState.java"
+ },
"1033274509": {
"message": "moveWindowTokenToDisplay: Attempted to move non-existing token: %s",
"level": "WARN",
@@ -2821,6 +2827,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1047505501": {
+ "message": "notifyInsetsChanged for %s ",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_WINDOW_INSETS",
+ "at": "com\/android\/server\/wm\/WindowState.java"
+ },
"1047769218": {
"message": "Finishing activity r=%s, result=%d, data=%s, reason=%s",
"level": "VERBOSE",
@@ -2941,6 +2953,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1210037962": {
+ "message": "Register remote animations for organizer=%s uid=%d pid=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+ },
"1219600119": {
"message": "addWindow: win=%s Callers=%s",
"level": "DEBUG",
@@ -3211,12 +3229,6 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "1533154777": {
- "message": "notifyInsetsChanged for %s ",
- "level": "DEBUG",
- "group": "WM_DEBUG_IME",
- "at": "com\/android\/server\/wm\/WindowState.java"
- },
"1557732761": {
"message": "For Intent %s bringing to top: %s",
"level": "DEBUG",
@@ -3643,6 +3655,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "2070726247": {
+ "message": "InsetsSource updateVisibility for %s, serverVisible: %s clientVisible: %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_WINDOW_INSETS",
+ "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+ },
"2083556954": {
"message": "Set mOrientationChanging of %s",
"level": "VERBOSE",
@@ -3768,6 +3786,9 @@
"WM_DEBUG_TASKS": {
"tag": "WindowManager"
},
+ "WM_DEBUG_WINDOW_INSETS": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_WINDOW_MOVEMENT": {
"tag": "WindowManager"
},
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
index 4206d0375e30..9212a0f5e6b9 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
@@ -62,6 +62,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
final Map<IBinder, Configuration> mFragmentParentConfigs = new ArrayMap<>();
private final TaskFragmentCallback mCallback;
+ private TaskFragmentAnimationController mAnimationController;
/**
* Callback that notifies the controller about changes to task fragments.
@@ -83,6 +84,25 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
mCallback = callback;
}
+ @Override
+ public void registerOrganizer() {
+ if (mAnimationController != null) {
+ throw new IllegalStateException("Must unregister the organizer before re-register.");
+ }
+ super.registerOrganizer();
+ mAnimationController = new TaskFragmentAnimationController(this);
+ mAnimationController.registerRemoteAnimations();
+ }
+
+ @Override
+ public void unregisterOrganizer() {
+ if (mAnimationController != null) {
+ mAnimationController.unregisterRemoteAnimations();
+ mAnimationController = null;
+ }
+ super.unregisterOrganizer();
+ }
+
/**
* Starts a new Activity and puts it into split with an existing Activity side-by-side.
* @param launchingFragmentToken token for the launching TaskFragment. If it exists, it will
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationController.java
new file mode 100644
index 000000000000..b85287d8a919
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationController.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.organizer;
+
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
+
+import android.util.Log;
+import android.view.RemoteAnimationAdapter;
+import android.view.RemoteAnimationDefinition;
+import android.window.TaskFragmentOrganizer;
+
+/** Controls the TaskFragment remote animations. */
+class TaskFragmentAnimationController {
+
+ private static final String TAG = "TaskFragAnimationCtrl";
+ // TODO(b/196173550) turn off when finalize
+ static final boolean DEBUG = false;
+
+ private final TaskFragmentOrganizer mOrganizer;
+ private final TaskFragmentAnimationRunner mRemoteRunner = new TaskFragmentAnimationRunner();
+
+ TaskFragmentAnimationController(TaskFragmentOrganizer organizer) {
+ mOrganizer = organizer;
+ }
+
+ void registerRemoteAnimations() {
+ if (DEBUG) {
+ Log.v(TAG, "registerRemoteAnimations");
+ }
+ final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter animationAdapter =
+ new RemoteAnimationAdapter(mRemoteRunner, 0, 0);
+ definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, animationAdapter);
+ definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, animationAdapter);
+ definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, animationAdapter);
+ mOrganizer.registerRemoteAnimations(definition);
+ }
+
+ void unregisterRemoteAnimations() {
+ if (DEBUG) {
+ Log.v(TAG, "unregisterRemoteAnimations");
+ }
+ mOrganizer.unregisterRemoteAnimations();
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationRunner.java
new file mode 100644
index 000000000000..9ee60d8c6bd3
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationRunner.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.organizer;
+
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IRemoteAnimationFinishedCallback;
+import android.view.IRemoteAnimationRunner;
+import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+
+import androidx.annotation.Nullable;
+
+/** To run the TaskFragment animations. */
+class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
+
+ private static final String TAG = "TaskFragAnimationRunner";
+ private final Handler mHandler = new Handler(Looper.myLooper());
+
+ @Nullable
+ private IRemoteAnimationFinishedCallback mFinishedCallback;
+
+ @Override
+ public void onAnimationStart(@WindowManager.TransitionOldType int transit,
+ RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers,
+ RemoteAnimationTarget[] nonApps,
+ IRemoteAnimationFinishedCallback finishedCallback) {
+ if (wallpapers.length != 0 || nonApps.length != 0) {
+ throw new IllegalArgumentException("TaskFragment shouldn't handle animation with"
+ + "wallpaper or non-app windows.");
+ }
+ if (TaskFragmentAnimationController.DEBUG) {
+ Log.v(TAG, "onAnimationStart transit=" + transit);
+ }
+ mHandler.post(() -> startAnimation(apps, finishedCallback));
+ }
+
+ @Override
+ public void onAnimationCancelled() {
+ if (TaskFragmentAnimationController.DEBUG) {
+ Log.v(TAG, "onAnimationCancelled");
+ }
+ mHandler.post(this::onAnimationFinished);
+ }
+
+ private void startAnimation(RemoteAnimationTarget[] targets,
+ IRemoteAnimationFinishedCallback finishedCallback) {
+ // TODO(b/196173550) replace with actual animations
+ mFinishedCallback = finishedCallback;
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ for (RemoteAnimationTarget target : targets) {
+ if (target.mode == MODE_OPENING) {
+ t.show(target.leash);
+ t.setAlpha(target.leash, 1);
+ }
+ t.setPosition(target.leash, target.localBounds.left, target.localBounds.top);
+ }
+ t.apply();
+ onAnimationFinished();
+ }
+
+ private void onAnimationFinished() {
+ if (mFinishedCallback == null) {
+ return;
+ }
+ try {
+ mFinishedCallback.onAnimationFinished();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ mFinishedCallback = null;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index a646b07c49dc..ae8c1b6f8c1a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -60,8 +60,7 @@ public class PhonePipMenuController implements PipMenuController {
private static final boolean DEBUG = false;
public static final int MENU_STATE_NONE = 0;
- public static final int MENU_STATE_CLOSE = 1;
- public static final int MENU_STATE_FULL = 2;
+ public static final int MENU_STATE_FULL = 1;
/**
* A listener interface to receive notification on changes in PIP.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 67b1e6dd4cc7..8ef2b6b12030 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -23,7 +23,6 @@ import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTR
import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
-import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_CLOSE;
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_FULL;
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_NONE;
@@ -203,7 +202,7 @@ public class PipMenuView extends FrameLayout {
@Override
public boolean performAccessibilityAction(View host, int action, Bundle args) {
- if (action == ACTION_CLICK && mMenuState == MENU_STATE_CLOSE) {
+ if (action == ACTION_CLICK && mMenuState != MENU_STATE_FULL) {
mController.showMenu();
}
return super.performAccessibilityAction(host, action, args);
@@ -271,13 +270,12 @@ public class PipMenuView extends FrameLayout {
mDismissButton.getAlpha(), 1f);
ObjectAnimator resizeAnim = ObjectAnimator.ofFloat(mResizeHandle, View.ALPHA,
mResizeHandle.getAlpha(),
- ENABLE_RESIZE_HANDLE && menuState == MENU_STATE_CLOSE && showResizeHandle
- ? 1f : 0f);
+ ENABLE_RESIZE_HANDLE && showResizeHandle ? 1f : 0f);
if (menuState == MENU_STATE_FULL) {
mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim,
resizeAnim);
} else {
- mMenuContainerAnimator.playTogether(dismissAnim, resizeAnim);
+ mMenuContainerAnimator.playTogether(resizeAnim);
}
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
mMenuContainerAnimator.setDuration(ANIMATION_HIDE_DURATION_MS);
@@ -429,7 +427,7 @@ public class PipMenuView extends FrameLayout {
FrameLayout.LayoutParams expandedLp =
(FrameLayout.LayoutParams) expandContainer.getLayoutParams();
- if (mActions.isEmpty() || menuState == MENU_STATE_CLOSE || menuState == MENU_STATE_NONE) {
+ if (mActions.isEmpty() || menuState == MENU_STATE_NONE) {
actionsContainer.setVisibility(View.INVISIBLE);
// Update the expand container margin to adjust the center of the expand button to
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 7867f933de4f..9f2f6a575aca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -22,7 +22,6 @@ import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTI
import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_LEFT;
import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_NONE;
import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT;
-import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_CLOSE;
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_FULL;
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_NONE;
import static com.android.wm.shell.pip.phone.PipMenuView.ANIM_TYPE_NONE;
@@ -81,7 +80,6 @@ public class PipTouchHandler {
private final PhonePipMenuController mMenuController;
private final AccessibilityManager mAccessibilityManager;
- private boolean mShowPipMenuOnAnimationEnd = false;
/**
* Whether PIP stash is enabled or not. When enabled, if the user flings toward the edge of the
@@ -280,7 +278,6 @@ public class PipTouchHandler {
public void onActivityPinned() {
mPipDismissTargetHandler.createOrUpdateDismissTarget();
- mShowPipMenuOnAnimationEnd = true;
mPipResizeGestureHandler.onActivityPinned();
mFloatingContentCoordinator.onContentAdded(mMotionHelper);
}
@@ -304,13 +301,6 @@ public class PipTouchHandler {
// Set the initial bounds as the user resize bounds.
mPipResizeGestureHandler.setUserResizeBounds(mPipBoundsState.getBounds());
}
-
- if (mShowPipMenuOnAnimationEnd) {
- mMenuController.showMenu(MENU_STATE_CLOSE, mPipBoundsState.getBounds(),
- true /* allowMenuTimeout */, false /* willResizeMenu */,
- shouldShowResizeHandle());
- mShowPipMenuOnAnimationEnd = false;
- }
}
public void onConfigurationChanged() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
index 1529f5bcd7e1..7a17bb3c3107 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -129,7 +129,7 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
}
/**
- * Expands the pip window and dismisses it by clicking on the X button.
+ * Taps the pip window and dismisses it by clicking on the X button.
*/
fun closePipWindow(wmHelper: WindowManagerStateHelper) {
if (isTelevision) {
@@ -137,9 +137,12 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
} else {
val windowRect = getWindowRect(wmHelper)
uiDevice.click(windowRect.centerX(), windowRect.centerY())
- val exitPipObject = uiDevice.findObject(By.res(SYSTEMUI_PACKAGE, "dismiss"))
+ // search and interact with the dismiss button
+ val dismissSelector = By.res(SYSTEMUI_PACKAGE, "dismiss")
+ uiDevice.wait(Until.hasObject(dismissSelector), FIND_TIMEOUT)
+ val dismissPipObject = uiDevice.findObject(dismissSelector)
?: error("PIP window dismiss button not found")
- val dismissButtonBounds = exitPipObject.visibleBounds
+ val dismissButtonBounds = dismissPipObject.visibleBounds
uiDevice.click(dismissButtonBounds.centerX(), dismissButtonBounds.centerY())
}
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 72cddc91f436..353556d70a19 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -50,6 +50,13 @@ public final class MediaProjection {
private final Context mContext;
private final Map<Callback, CallbackRecord> mCallbacks;
+ /**
+ * Store the WindowContext in a field. If it is a local variable, and it is garbage collected
+ * during a MediaProjection session, the WindowContainer listener no longer exists.
+ */
+ @Nullable
+ private Context mWindowContext;
+
/** @hide */
public MediaProjection(Context context, IMediaProjection impl) {
mCallbacks = new ArrayMap<Callback, CallbackRecord>();
@@ -162,11 +169,11 @@ public final class MediaProjection {
*/
private VirtualDisplayConfig.Builder buildMirroredVirtualDisplay(@NonNull String name,
int width, int height, int dpi) {
- Context windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
+ mWindowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
TYPE_APPLICATION, null /* options */);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
height, dpi);
- builder.setWindowTokenClientToMirror(windowContext.getWindowContextToken());
+ builder.setWindowTokenClientToMirror(mWindowContext.getWindowContextToken());
return builder;
}
diff --git a/packages/SystemUI/res/layout/communal_host_view.xml b/packages/SystemUI/res/layout/communal_host_view.xml
index 4406a46c3537..cd9c26065dc1 100644
--- a/packages/SystemUI/res/layout/communal_host_view.xml
+++ b/packages/SystemUI/res/layout/communal_host_view.xml
@@ -18,13 +18,6 @@
<!-- This is a view that shows general status information in Keyguard. -->
<com.android.systemui.communal.CommunalHostView
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/communal_host"
- android:orientation="vertical"
- systemui:layout_constraintEnd_toEndOf="parent"
- systemui:layout_constraintStart_toStartOf="parent"
- systemui:layout_constraintTop_toTopOf="parent"
- systemui:layout_constraintBottom_toBottomOf="parent"
- systemui:layout_constraintHeight_percent="@dimen/communal_source_height_percentage"
- android:layout_width="0dp"
- android:layout_height="0dp"/> \ No newline at end of file
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
index cc44b5e5df38..b1e8c386fe21 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
@@ -49,6 +49,11 @@
/>
</FrameLayout>
+ <!-- We want this to be centered (to align with notches). In order to do that, the following
+ has to hold (in portrait):
+ * date_container and privacy_container must have the same width and weight
+ * header_text_container must be gone
+ -->
<android.widget.Space
android:id="@+id/space"
android:layout_width="0dp"
@@ -75,7 +80,7 @@
android:layout_weight="1"
android:gravity="center_vertical|end" >
- <include layout="@layout/ongoing_privacy_chip" />
+ <include layout="@layout/ongoing_privacy_chip" />
</FrameLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 7513af32d832..9821fb05df1d 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -25,6 +25,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent">
+
+ <include layout="@layout/communal_host_view"
+ android:visibility="gone"/>
+
<FrameLayout
android:id="@+id/big_clock_container"
android:layout_width="match_parent"
@@ -125,9 +129,6 @@
systemui:layout_constraintEnd_toEndOf="parent"
/>
- <include layout="@layout/communal_host_view"
- android:visibility="gone"/>
-
<include layout="@layout/ambient_indication"
android:id="@+id/ambient_indication_container" />
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index 9b5eae8f6c26..49cd279fb4be 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -29,6 +29,7 @@ import com.android.systemui.unfold.progress.FixedTimingTransitionProgressProvide
import com.android.systemui.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider
import com.android.systemui.unfold.updates.DeviceFoldStateProvider
import com.android.systemui.unfold.updates.hinge.EmptyHingeAngleProvider
+import com.android.systemui.unfold.updates.hinge.HingeSensorAngleProvider
import com.android.systemui.unfold.updates.hinge.RotationSensorHingeAngleProvider
import java.lang.IllegalStateException
import java.util.concurrent.Executor
@@ -50,7 +51,13 @@ fun createUnfoldTransitionProgressProvider(
val hingeAngleProvider =
if (config.mode == ANIMATION_MODE_HINGE_ANGLE) {
- RotationSensorHingeAngleProvider(sensorManager)
+ // TODO: after removing temporary "config.mode" we should just
+ // switch between fixed timing and hinge sensor based on this flag
+ if (config.isHingeAngleEnabled) {
+ HingeSensorAngleProvider(sensorManager)
+ } else {
+ RotationSensorHingeAngleProvider(sensorManager)
+ }
} else {
EmptyHingeAngleProvider()
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
index fa6b5de0b1ee..e7c6998a847e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
@@ -25,6 +25,9 @@ internal class ResourceUnfoldTransitionConfig(
override val isEnabled: Boolean
get() = readIsEnabled() && mode != ANIMATION_MODE_DISABLED
+ override val isHingeAngleEnabled: Boolean
+ get() = readIsHingeAngleEnabled()
+
@AnimationMode
override val mode: Int
get() = SystemProperties.getInt(UNFOLD_TRANSITION_MODE_PROPERTY_NAME,
@@ -32,6 +35,9 @@ internal class ResourceUnfoldTransitionConfig(
private fun readIsEnabled(): Boolean = context.resources
.getBoolean(com.android.internal.R.bool.config_unfoldTransitionEnabled)
+
+ private fun readIsHingeAngleEnabled(): Boolean = context.resources
+ .getBoolean(com.android.internal.R.bool.config_unfoldTransitionHingeAngle)
}
/**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
index 75d9dc32339f..a5697578e05a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
@@ -19,6 +19,7 @@ import android.annotation.IntDef
interface UnfoldTransitionConfig {
val isEnabled: Boolean
+ val isHingeAngleEnabled: Boolean
@AnimationMode
val mode: Int
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
index b111892ceb6e..10e6c2bfea3a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -16,6 +16,7 @@
package com.android.systemui.unfold.progress
import android.os.Handler
+import android.util.MathUtils.saturate
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.FloatPropertyCompat
import androidx.dynamicanimation.animation.SpringAnimation
@@ -24,6 +25,7 @@ import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
+import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
import com.android.systemui.unfold.updates.FoldStateProvider
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
@@ -33,7 +35,6 @@ import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
* Maps fold updates to unfold transition progress using DynamicAnimation.
*
* TODO(b/193793338) Current limitations:
- * - doesn't handle folding transition
* - doesn't handle postures
*/
internal class PhysicsBasedUnfoldTransitionProgressProvider(
@@ -75,14 +76,20 @@ internal class PhysicsBasedUnfoldTransitionProgressProvider(
override fun onHingeAngleUpdate(angle: Float) {
if (!isTransitionRunning || isAnimatedCancelRunning) return
- springAnimation.animateToFinalPosition(angle / 180f)
+ val progress = saturate(angle / FINAL_HINGE_ANGLE_POSITION)
+ springAnimation.animateToFinalPosition(progress)
}
override fun onFoldUpdate(@FoldUpdate update: Int) {
when (update) {
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> {
- onStartTransition()
startTransition(startValue = 0f)
+
+ // Stop the animation if the device has already opened by the time when
+ // the display is available as we won't receive the full open event anymore
+ if (foldStateProvider.isFullyOpened) {
+ cancelTransition(endValue = 1f, animate = true)
+ }
}
FOLD_UPDATE_FINISH_FULL_OPEN -> {
cancelTransition(endValue = 1f, animate = true)
@@ -90,13 +97,16 @@ internal class PhysicsBasedUnfoldTransitionProgressProvider(
FOLD_UPDATE_FINISH_CLOSED -> {
cancelTransition(endValue = 0f, animate = false)
}
+ FOLD_UPDATE_START_CLOSING -> {
+ startTransition(startValue = 1f)
+ }
}
}
private fun cancelTransition(endValue: Float, animate: Boolean) {
handler.removeCallbacks(timeoutRunnable)
- if (animate) {
+ if (isTransitionRunning && animate) {
isAnimatedCancelRunning = true
springAnimation.animateToFinalPosition(endValue)
} else {
@@ -182,3 +192,4 @@ internal class PhysicsBasedUnfoldTransitionProgressProvider(
private const val TRANSITION_TIMEOUT_MILLIS = 2000L
private const val SPRING_STIFFNESS = 200.0f
private const val MINIMAL_VISIBLE_CHANGE = 0.001f
+private const val FINAL_HINGE_ANGLE_POSITION = 165f
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 949652bc9137..c37ab06abb60 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -68,20 +68,29 @@ internal class DeviceFoldStateProvider(
outputListeners.remove(listener)
}
+ override val isFullyOpened: Boolean
+ get() = !isFolded && lastFoldUpdate == FOLD_UPDATE_FINISH_FULL_OPEN
+
private fun onHingeAngle(angle: Float) {
when (lastFoldUpdate) {
FOLD_UPDATE_FINISH_FULL_OPEN -> {
- if (FULLY_OPEN_DEGREES - angle > MOVEMENT_THRESHOLD_DEGREES) {
+ if (FULLY_OPEN_DEGREES - angle > START_CLOSING_THRESHOLD_DEGREES) {
lastFoldUpdate = FOLD_UPDATE_START_CLOSING
outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_START_CLOSING) }
}
}
- FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING -> {
+ FOLD_UPDATE_START_OPENING -> {
if (FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES) {
lastFoldUpdate = FOLD_UPDATE_FINISH_FULL_OPEN
outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) }
}
}
+ FOLD_UPDATE_START_CLOSING -> {
+ if (FULLY_OPEN_DEGREES - angle < START_CLOSING_THRESHOLD_DEGREES) {
+ lastFoldUpdate = FOLD_UPDATE_FINISH_FULL_OPEN
+ outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) }
+ }
+ }
}
outputListeners.forEach { it.onHingeAngleUpdate(angle) }
@@ -120,5 +129,5 @@ internal class DeviceFoldStateProvider(
}
}
-private const val MOVEMENT_THRESHOLD_DEGREES = 10f
-private const val FULLY_OPEN_THRESHOLD_DEGREES = 10f \ No newline at end of file
+private const val START_CLOSING_THRESHOLD_DEGREES = 95f
+private const val FULLY_OPEN_THRESHOLD_DEGREES = 15f \ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
index 4c6d241b1456..11984b93638e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
@@ -28,6 +28,8 @@ internal interface FoldStateProvider : CallbackController<FoldUpdatesListener> {
fun start()
fun stop()
+ val isFullyOpened: Boolean
+
interface FoldUpdatesListener {
fun onHingeAngleUpdate(@FloatRange(from = 0.0, to = 180.0) angle: Float)
fun onFoldUpdate(@FoldUpdate update: Int)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt
index 854991383a8c..2520d356b721 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt
@@ -3,6 +3,12 @@ package com.android.systemui.unfold.updates.hinge
import androidx.core.util.Consumer
import com.android.systemui.statusbar.policy.CallbackController
+/**
+ * Emits device hinge angle values (angle between two integral parts of the device).
+ * The hinge angle could be from 0 to 360 degrees inclusive.
+ * For foldable devices usually 0 corresponds to fully closed (folded) state and
+ * 180 degrees corresponds to fully open (flat) state
+ */
internal interface HingeAngleProvider : CallbackController<Consumer<Float>> {
fun start()
fun stop()
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
new file mode 100644
index 000000000000..a42ebef04de1
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
@@ -0,0 +1,42 @@
+package com.android.systemui.unfold.updates.hinge
+
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import androidx.core.util.Consumer
+
+internal class HingeSensorAngleProvider(
+ private val sensorManager: SensorManager
+) : HingeAngleProvider {
+
+ private val sensorListener = HingeAngleSensorListener()
+ private val listeners: MutableList<Consumer<Float>> = arrayListOf()
+
+ override fun start() {
+ val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE)
+ sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_FASTEST)
+ }
+
+ override fun stop() {
+ sensorManager.unregisterListener(sensorListener)
+ }
+
+ override fun removeCallback(listener: Consumer<Float>) {
+ listeners.remove(listener)
+ }
+
+ override fun addCallback(listener: Consumer<Float>) {
+ listeners.add(listener)
+ }
+
+ private inner class HingeAngleSensorListener : SensorEventListener {
+
+ override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
+ }
+
+ override fun onSensorChanged(event: SensorEvent) {
+ listeners.forEach { it.accept(event.values[0]) }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java
index 0b0e430dab94..153da4b6695a 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java
@@ -19,6 +19,7 @@ package com.android.keyguard.dagger;
import com.android.keyguard.KeyguardStatusViewController;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController;
+import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import dagger.BindsInstance;
import dagger.Subcomponent;
@@ -36,8 +37,8 @@ public interface KeyguardStatusBarViewComponent {
interface Factory {
KeyguardStatusBarViewComponent build(
@BindsInstance KeyguardStatusBarView view,
- @BindsInstance KeyguardStatusBarViewController.ViewStateProvider
- viewStateProvider);
+ @BindsInstance NotificationPanelViewController.NotificationPanelViewStateProvider
+ notificationPanelViewStateProvider);
}
/** Builds a {@link KeyguardStatusViewController}. */
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
index 07f765b01027..ba6373c5bd20 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
@@ -160,6 +160,21 @@ public class CommunalHostViewController extends ViewController<CommunalHostView>
statusBarState, keyguardFadingAway, goingToFullShade, oldStatusBarState);
}
+ /**
+ * Set keyguard status view alpha.
+ */
+ public void setAlpha(float alpha) {
+ if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
+ mView.setAlpha(alpha);
+
+ // Some communal view implementations, such as SurfaceViews, do not behave correctly
+ // inheriting the alpha of their parent. Directly set child alpha here to work around
+ // this.
+ for (int i = mView.getChildCount() - 1; i >= 0; --i) {
+ mView.getChildAt(i).setAlpha(alpha);
+ }
+ }
+ }
@Override
public void init() {
super.init();
diff --git a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSurfaceViewController.java b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSurfaceViewController.java
index 89239cfd1349..4927e0908c5a 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSurfaceViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSurfaceViewController.java
@@ -124,8 +124,7 @@ public class CommunalSurfaceViewController extends ViewController<SurfaceView> {
}
@Override
- public void init() {
- super.init();
+ protected void onInit() {
mView.getHolder().addCallback(mSurfaceHolderCallback);
mView.addOnLayoutChangeListener(mOnLayoutChangeListener);
}
@@ -164,9 +163,6 @@ public class CommunalSurfaceViewController extends ViewController<SurfaceView> {
mNotificationShadeWindowController.setTouchExclusionRegion(emptyRegion);
emptyRegion.recycle();
}
- // TODO(b/197036940): This is no longer necessary once the surface view is not on top of the
- // z-order.
- mView.setZOrderOnTop(excludeTouches);
}
private void showSurface(boolean show) {
@@ -208,7 +204,6 @@ public class CommunalSurfaceViewController extends ViewController<SurfaceView> {
if (surfacePackage != null) {
mView.setChildSurfacePackage(surfacePackage);
- mView.setZOrderOnTop(true);
mView.postInvalidate();
mCommunalStateController.setCommunalViewShowing(true);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index c093219de59b..e7974bc3e6c9 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -196,9 +196,11 @@ public class DependencyProvider {
@SysUISingleton
@Provides
static ThemeOverlayApplier provideThemeOverlayManager(Context context,
- @Background Executor bgExecutor, OverlayManager overlayManager,
+ @Background Executor bgExecutor,
+ @Main Executor mainExecutor,
+ OverlayManager overlayManager,
DumpManager dumpManager) {
- return new ThemeOverlayApplier(overlayManager, bgExecutor,
+ return new ThemeOverlayApplier(overlayManager, bgExecutor, mainExecutor,
context.getString(R.string.launcher_overlayable_package),
context.getString(R.string.themepicker_overlayable_package), dumpManager);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index a85800bfa76e..7eedb3a91c82 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -140,6 +140,10 @@ public class QuickStatusBarHeader extends FrameLayout {
mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon);
updateResources();
+ Configuration config = mContext.getResources().getConfiguration();
+ setDatePrivacyContainersWidth(config.orientation == Configuration.ORIENTATION_LANDSCAPE);
+ setSecurityHeaderContainerVisibility(
+ config.orientation == Configuration.ORIENTATION_LANDSCAPE);
// QS will always show the estimate, and BatteryMeterView handles the case where
// it's unavailable or charging
@@ -189,6 +193,8 @@ public class QuickStatusBarHeader extends FrameLayout {
super.onConfigurationChanged(newConfig);
updateResources();
setDatePrivacyContainersWidth(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE);
+ setSecurityHeaderContainerVisibility(
+ newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE);
}
@Override
@@ -209,6 +215,10 @@ public class QuickStatusBarHeader extends FrameLayout {
mPrivacyContainer.setLayoutParams(lp);
}
+ private void setSecurityHeaderContainerVisibility(boolean landscape) {
+ mSecurityHeaderView.setVisibility(landscape ? VISIBLE : GONE);
+ }
+
private void updateBatteryMode() {
if (mConfigShowBatteryEstimate && !mHasCenterCutout) {
mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index dfe78de81f7f..62fa3d4ac819 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -391,7 +391,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback,
level += 1;
numLevels += 1;
}
- return getSignalStrengthIcon(mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON, false);
+ return getSignalStrengthIcon(mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON,
+ !isMobileDataEnabled());
}
Drawable getSignalStrengthIcon(Context context, int level, int numLevels,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index af9d92113c5c..893aa6d6bc45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -25,6 +25,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.res.Resources;
import android.hardware.biometrics.BiometricSourceType;
+import android.util.MathUtils;
import android.view.View;
import androidx.annotation.NonNull;
@@ -40,6 +41,9 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -57,6 +61,21 @@ import javax.inject.Inject;
/** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */
public class KeyguardStatusBarViewController extends ViewController<KeyguardStatusBarView> {
+ private static final AnimationProperties KEYGUARD_HUN_PROPERTIES =
+ new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+
+ private float mKeyguardHeadsUpShowingAmount = 0.0f;
+ private final AnimatableProperty mHeadsUpShowingAmountAnimation = AnimatableProperty.from(
+ "KEYGUARD_HEADS_UP_SHOWING_AMOUNT",
+ (view, aFloat) -> {
+ mKeyguardHeadsUpShowingAmount = aFloat;
+ updateViewState();
+ },
+ view -> mKeyguardHeadsUpShowingAmount,
+ R.id.keyguard_hun_animator_tag,
+ R.id.keyguard_hun_animator_end_tag,
+ R.id.keyguard_hun_animator_start_tag);
+
private final CarrierTextController mCarrierTextController;
private final ConfigurationController mConfigurationController;
private final SystemStatusAnimationScheduler mAnimationScheduler;
@@ -65,7 +84,8 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
private final StatusBarIconController mStatusBarIconController;
private final StatusBarIconController.TintedIconManager.Factory mTintedIconManagerFactory;
private final BatteryMeterViewController mBatteryMeterViewController;
- private final ViewStateProvider mViewStateProvider;
+ private final NotificationPanelViewController.NotificationPanelViewStateProvider
+ mNotificationPanelViewStateProvider;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardBypassController mKeyguardBypassController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -176,6 +196,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
};
private final List<String> mBlockedIcons;
+ private final int mNotificationsHeaderCollideDistance;
private boolean mBatteryListening;
private StatusBarIconController.TintedIconManager mTintedIconManager;
@@ -193,6 +214,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
private boolean mDelayShowingKeyguardStatusBar;
private int mStatusBarState;
private boolean mDozing;
+ private boolean mShowingKeyguardHeadsUp;
@Inject
public KeyguardStatusBarViewController(
@@ -205,7 +227,8 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
StatusBarIconController statusBarIconController,
StatusBarIconController.TintedIconManager.Factory tintedIconManagerFactory,
BatteryMeterViewController batteryMeterViewController,
- ViewStateProvider viewStateProvider,
+ NotificationPanelViewController.NotificationPanelViewStateProvider
+ notificationPanelViewStateProvider,
KeyguardStateController keyguardStateController,
KeyguardBypassController bypassController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -220,7 +243,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
mStatusBarIconController = statusBarIconController;
mTintedIconManagerFactory = tintedIconManagerFactory;
mBatteryMeterViewController = batteryMeterViewController;
- mViewStateProvider = viewStateProvider;
+ mNotificationPanelViewStateProvider = notificationPanelViewStateProvider;
mKeyguardStateController = keyguardStateController;
mKeyguardBypassController = bypassController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -245,6 +268,8 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
r.getString(com.android.internal.R.string.status_bar_volume),
r.getString(com.android.internal.R.string.status_bar_alarm_clock),
r.getString(com.android.internal.R.string.status_bar_call_strength)));
+ mNotificationsHeaderCollideDistance = r.getDimensionPixelSize(
+ R.dimen.header_notifications_collide_distance);
}
@Override
@@ -355,16 +380,20 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
}
/**
- * Updates the {@link KeyguardStatusBarView} state based on what the {@link ViewStateProvider}
- * and other controllers provide.
+ * Updates the {@link KeyguardStatusBarView} state based on what the
+ * {@link NotificationPanelViewController.NotificationPanelViewStateProvider} and other
+ * controllers provide.
*/
public void updateViewState() {
- ViewState newViewState = mViewStateProvider.provideViewState();
if (!isKeyguardShowing()) {
return;
}
- float newAlpha = newViewState.mAlpha * mKeyguardStatusBarAnimateAlpha;
+ float alphaQsExpansion = 1 - Math.min(
+ 1, mNotificationPanelViewStateProvider.getQsExpansionFraction() * 2);
+ float newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
+ * mKeyguardStatusBarAnimateAlpha
+ * (1.0f - mKeyguardHeadsUpShowingAmount);
boolean hideForBypass =
mFirstBypassAttempt && mKeyguardUpdateMonitor.shouldListenForFace()
@@ -383,6 +412,54 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
mView.setVisibility(visibility);
}
+ /**
+ * @return the alpha to be used to fade out the contents on Keyguard (status bar, bottom area)
+ * during swiping up.
+ */
+ private float getKeyguardContentsAlpha() {
+ float alpha;
+ if (isKeyguardShowing()) {
+ // When on Keyguard, we hide the header as soon as we expanded close enough to the
+ // header
+ alpha = mNotificationPanelViewStateProvider.getPanelViewExpandedHeight()
+ / (mView.getHeight() + mNotificationsHeaderCollideDistance);
+ } else {
+ // In SHADE_LOCKED, the top card is already really close to the header. Hide it as
+ // soon as we start translating the stack.
+ alpha = mNotificationPanelViewStateProvider.getPanelViewExpandedHeight()
+ / mView.getHeight();
+ }
+ alpha = MathUtils.saturate(alpha);
+ alpha = (float) Math.pow(alpha, 0.75);
+ return alpha;
+ }
+
+ /**
+ * Update {@link KeyguardStatusBarView}'s visibility based on whether keyguard is showing and
+ * whether heads up is visible.
+ */
+ public void updateForHeadsUp() {
+ updateForHeadsUp(true);
+ }
+
+ void updateForHeadsUp(boolean animate) {
+ boolean showingKeyguardHeadsUp =
+ isKeyguardShowing() && mNotificationPanelViewStateProvider.shouldHeadsUpBeVisible();
+ if (mShowingKeyguardHeadsUp != showingKeyguardHeadsUp) {
+ mShowingKeyguardHeadsUp = showingKeyguardHeadsUp;
+ if (isKeyguardShowing()) {
+ PropertyAnimator.setProperty(
+ mView,
+ mHeadsUpShowingAmountAnimation,
+ showingKeyguardHeadsUp ? 1.0f : 0.0f,
+ KEYGUARD_HUN_PROPERTIES,
+ animate);
+ } else {
+ PropertyAnimator.applyImmediately(mView, mHeadsUpShowingAmountAnimation, 0.0f);
+ }
+ }
+ }
+
private boolean isKeyguardShowing() {
return mStatusBarState == KEYGUARD;
}
@@ -394,18 +471,4 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
mView.dump(fd, pw, args);
}
- /** An interface that provides the desired state of {@link KeyguardStatusBarView}. */
- public interface ViewStateProvider {
- /** Provides the state. */
- ViewState provideViewState();
- }
-
- /** A POJO for the desired state of {@link KeyguardStatusBarView}. */
- static class ViewState {
- final float mAlpha;
-
- ViewState(float alpha) {
- this.mAlpha = alpha;
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 0faf520103de..09eb5c4bea6f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -190,7 +190,6 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
-import java.util.function.Function;
import javax.inject.Inject;
import javax.inject.Provider;
@@ -271,17 +270,6 @@ public class NotificationPanelViewController extends PanelViewController {
private static final Rect M_DUMMY_DIRTY_RECT = new Rect(0, 0, 1, 1);
private static final Rect EMPTY_RECT = new Rect();
- private final AnimatableProperty KEYGUARD_HEADS_UP_SHOWING_AMOUNT = AnimatableProperty.from(
- "KEYGUARD_HEADS_UP_SHOWING_AMOUNT",
- (notificationPanelView, aFloat) -> setKeyguardHeadsUpShowingAmount(aFloat),
- (Function<NotificationPanelView, Float>) notificationPanelView ->
- getKeyguardHeadsUpShowingAmount(),
- R.id.keyguard_hun_animator_tag, R.id.keyguard_hun_animator_end_tag,
- R.id.keyguard_hun_animator_start_tag);
- private static final AnimationProperties
- KEYGUARD_HUN_PROPERTIES =
- new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
-
private final LayoutInflater mLayoutInflater;
private final PowerManager mPowerManager;
private final AccessibilityManager mAccessibilityManager;
@@ -380,7 +368,6 @@ public class NotificationPanelViewController extends PanelViewController {
private FlingAnimationUtils mFlingAnimationUtils;
private int mStatusBarMinHeight;
private int mStatusBarHeaderHeightKeyguard;
- private int mNotificationsHeaderCollideDistance;
private float mOverStretchAmount;
private float mDownX;
private float mDownY;
@@ -532,8 +519,6 @@ public class NotificationPanelViewController extends PanelViewController {
private int mDarkIconSize;
private int mHeadsUpInset;
private boolean mHeadsUpPinnedMode;
- private float mKeyguardHeadsUpShowingAmount = 0.0f;
- private boolean mShowingKeyguardHeadsUp;
private boolean mAllowExpandForSmallExpansion;
private Runnable mExpandAfterLayoutRunnable;
@@ -702,17 +687,6 @@ public class NotificationPanelViewController extends PanelViewController {
}
};
- private final KeyguardStatusBarViewController.ViewStateProvider mViewStateProvider =
- new KeyguardStatusBarViewController.ViewStateProvider() {
- @Override
- public KeyguardStatusBarViewController.ViewState provideViewState() {
- float alphaQsExpansion = 1 - Math.min(1, computeQsExpansionFraction() * 2);
- float newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
- * (1.0f - mKeyguardHeadsUpShowingAmount);
- return new KeyguardStatusBarViewController.ViewState(newAlpha);
- }
- };
-
@Inject
public NotificationPanelViewController(NotificationPanelView view,
@Main Resources resources,
@@ -912,7 +886,7 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardStatusBarViewController =
mKeyguardStatusBarViewComponentFactory.build(
mKeyguardStatusBar,
- mViewStateProvider)
+ mNotificationPanelViewStateProvider)
.getKeyguardStatusBarViewController();
mKeyguardStatusBarViewController.init();
@@ -952,7 +926,7 @@ public class NotificationPanelViewController extends PanelViewController {
mWakeUpCoordinator.addListener(new NotificationWakeUpCoordinator.WakeUpListener() {
@Override
public void onFullyHiddenChanged(boolean isFullyHidden) {
- updateKeyguardStatusBarForHeadsUp();
+ mKeyguardStatusBarViewController.updateForHeadsUp();
}
@Override
@@ -989,8 +963,6 @@ public class NotificationPanelViewController extends PanelViewController {
mStatusBarHeaderHeightKeyguard = mResources.getDimensionPixelSize(
R.dimen.status_bar_header_height_keyguard);
mQsPeekHeight = mResources.getDimensionPixelSize(R.dimen.qs_peek_height);
- mNotificationsHeaderCollideDistance = mResources.getDimensionPixelSize(
- R.dimen.header_notifications_collide_distance);
mClockPositionAlgorithm.loadDimens(mResources);
mQsFalsingThreshold = mResources.getDimensionPixelSize(R.dimen.qs_falsing_threshold);
mPositionMinSideMargin = mResources.getDimensionPixelSize(
@@ -1574,6 +1546,12 @@ public class NotificationPanelViewController extends PanelViewController {
return true;
}
+ private void updateCommunal() {
+ if (mCommunalViewController != null) {
+ mCommunalViewController.setAlpha(mKeyguardOnlyContentAlpha);
+ }
+ }
+
private void updateClock() {
float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha;
mKeyguardStatusViewController.setAlpha(alpha);
@@ -2675,6 +2653,7 @@ public class NotificationPanelViewController extends PanelViewController {
updateKeyguardBottomAreaAlpha();
}
updateClock();
+ updateCommunal();
}
private void trackMovement(MotionEvent event) {
@@ -3027,30 +3006,6 @@ public class NotificationPanelViewController extends PanelViewController {
return Math.min(0, translation);
}
- /**
- * @return the alpha to be used to fade out the contents on Keyguard (status bar, bottom area)
- * during swiping up
- */
- private float getKeyguardContentsAlpha() {
- float alpha;
- if (mBarState == KEYGUARD) {
-
- // When on Keyguard, we hide the header as soon as we expanded close enough to the
- // header
- alpha =
- getExpandedHeight() / (mKeyguardStatusBar.getHeight()
- + mNotificationsHeaderCollideDistance);
- } else {
-
- // In SHADE_LOCKED, the top card is already really close to the header. Hide it as
- // soon as we start translating the stack.
- alpha = getExpandedHeight() / mKeyguardStatusBar.getHeight();
- }
- alpha = MathUtils.saturate(alpha);
- alpha = (float) Math.pow(alpha, 0.75);
- return alpha;
- }
-
private void updateKeyguardBottomAreaAlpha() {
// There are two possible panel expansion behaviors:
// • User dragging up to unlock: we want to fade out as quick as possible
@@ -3346,31 +3301,6 @@ public class NotificationPanelViewController extends PanelViewController {
mPanelAlphaEndAction = r;
}
- private void updateKeyguardStatusBarForHeadsUp() {
- boolean
- showingKeyguardHeadsUp =
- mKeyguardShowing && mHeadsUpAppearanceController.shouldBeVisible();
- if (mShowingKeyguardHeadsUp != showingKeyguardHeadsUp) {
- mShowingKeyguardHeadsUp = showingKeyguardHeadsUp;
- if (mKeyguardShowing) {
- PropertyAnimator.setProperty(mView, KEYGUARD_HEADS_UP_SHOWING_AMOUNT,
- showingKeyguardHeadsUp ? 1.0f : 0.0f, KEYGUARD_HUN_PROPERTIES,
- true /* animate */);
- } else {
- PropertyAnimator.applyImmediately(mView, KEYGUARD_HEADS_UP_SHOWING_AMOUNT, 0.0f);
- }
- }
- }
-
- private void setKeyguardHeadsUpShowingAmount(float amount) {
- mKeyguardHeadsUpShowingAmount = amount;
- mKeyguardStatusBarViewController.updateViewState();
- }
-
- private float getKeyguardHeadsUpShowingAmount() {
- return mKeyguardHeadsUpShowingAmount;
- }
-
public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
mHeadsUpAnimatingAway = headsUpAnimatingAway;
mNotificationStackScrollLayoutController.setHeadsUpAnimatingAway(headsUpAnimatingAway);
@@ -4351,7 +4281,7 @@ public class NotificationPanelViewController extends PanelViewController {
updateGestureExclusionRect();
mHeadsUpPinnedMode = inPinnedMode;
updateHeadsUpVisibility();
- updateKeyguardStatusBarForHeadsUp();
+ mKeyguardStatusBarViewController.updateForHeadsUp();
}
@Override
@@ -4519,7 +4449,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
}
}
- updateKeyguardStatusBarForHeadsUp();
+ mKeyguardStatusBarViewController.updateForHeadsUp();
if (keyguardShowing) {
updateDozingVisibilities(false /* animate */);
}
@@ -4545,6 +4475,43 @@ public class NotificationPanelViewController extends PanelViewController {
}
/**
+ * An interface that provides the current state of the notification panel and related views,
+ * which is needed to calculate {@link KeyguardStatusBarView}'s state in
+ * {@link KeyguardStatusBarViewController}.
+ */
+ public interface NotificationPanelViewStateProvider {
+ /** Returns the expanded height of the panel view. */
+ float getPanelViewExpandedHeight();
+ /** Returns the fraction of QS that's expanded. */
+ float getQsExpansionFraction();
+ /**
+ * Returns true if heads up should be visible.
+ *
+ * TODO(b/138786270): If HeadsUpAppearanceController was injectable, we could inject it into
+ * {@link KeyguardStatusBarViewController} and remove this method.
+ */
+ boolean shouldHeadsUpBeVisible();
+ }
+
+ private final NotificationPanelViewStateProvider mNotificationPanelViewStateProvider =
+ new NotificationPanelViewStateProvider() {
+ @Override
+ public float getPanelViewExpandedHeight() {
+ return getExpandedHeight();
+ }
+
+ @Override
+ public float getQsExpansionFraction() {
+ return computeQsExpansionFraction();
+ }
+
+ @Override
+ public boolean shouldHeadsUpBeVisible() {
+ return mHeadsUpAppearanceController.shouldBeVisible();
+ }
+ };
+
+ /**
* Reconfigures the shade to show the AOD UI (clock, smartspace, etc). This is called by the
* screen off animation controller in order to animate in AOD without "actually" fully switching
* to the KEYGUARD state, which is a heavy transition that causes jank as 10+ files react to the
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
index c3b4fbe9a13d..fe0b97056024 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
@@ -132,14 +132,18 @@ public class ThemeOverlayApplier implements Dumpable {
/* Target package for each overlay category. */
private final Map<String, String> mCategoryToTargetPackage = new ArrayMap<>();
private final OverlayManager mOverlayManager;
- private final Executor mExecutor;
+ private final Executor mBgExecutor;
+ private final Executor mMainExecutor;
private final String mLauncherPackage;
private final String mThemePickerPackage;
- public ThemeOverlayApplier(OverlayManager overlayManager, Executor executor,
+ public ThemeOverlayApplier(OverlayManager overlayManager,
+ Executor bgExecutor,
+ Executor mainExecutor,
String launcherPackage, String themePickerPackage, DumpManager dumpManager) {
mOverlayManager = overlayManager;
- mExecutor = executor;
+ mBgExecutor = bgExecutor;
+ mMainExecutor = mainExecutor;
mLauncherPackage = launcherPackage;
mThemePickerPackage = themePickerPackage;
mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet(
@@ -170,12 +174,13 @@ public class ThemeOverlayApplier implements Dumpable {
* Apply the set of overlay packages to the set of {@code UserHandle}s provided. Overlays that
* affect sysui will also be applied to the system user.
*/
- void applyCurrentUserOverlays(
+ public void applyCurrentUserOverlays(
Map<String, OverlayIdentifier> categoryToPackage,
FabricatedOverlay[] pendingCreation,
int currentUser,
- Set<UserHandle> managedProfiles) {
- mExecutor.execute(() -> {
+ Set<UserHandle> managedProfiles,
+ Runnable onOverlaysApplied) {
+ mBgExecutor.execute(() -> {
// Disable all overlays that have not been specified in the user setting.
final Set<String> overlayCategoriesToDisable = new HashSet<>(THEME_CATEGORIES);
@@ -221,6 +226,7 @@ public class ThemeOverlayApplier implements Dumpable {
try {
mOverlayManager.commit(transaction.build());
+ mMainExecutor.execute(onOverlaysApplied);
} catch (SecurityException | IllegalStateException e) {
Log.e(TAG, "setEnabled failed", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 377a7e65d0a4..a5871f0ccbe6 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -526,16 +526,16 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
.map(key -> key + " -> " + categoryToPackage.get(key)).collect(
Collectors.joining(", ")));
}
+ Runnable overlaysAppliedRunnable = () -> onOverlaysApplied();
if (mNeedsOverlayCreation) {
mNeedsOverlayCreation = false;
mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[] {
mSecondaryOverlay, mNeutralOverlay
- }, currentUser, managedProfiles);
+ }, currentUser, managedProfiles, overlaysAppliedRunnable);
} else {
mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, currentUser,
- managedProfiles);
+ managedProfiles, overlaysAppliedRunnable);
}
- onOverlaysApplied();
}
protected void onOverlaysApplied() {
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
index 9283403edd1a..3c3cc64a49cd 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
@@ -58,6 +58,10 @@ class UnfoldLightRevealOverlayAnimation @Inject constructor(
}
override fun onTransitionStarted() {
+ // When unfolding the view is added earlier, add view for folding case
+ if (scrimView == null) {
+ addOverlayView()
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
index b7128325a640..3b750e7c1c2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
@@ -77,6 +77,9 @@ public class CommunalHostViewControllerTest extends SysuiTestCase {
@Mock
private CommunalSource mCommunalSource;
+ @Mock
+ private View mChildView;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -211,4 +214,16 @@ public class CommunalHostViewControllerTest extends SysuiTestCase {
// Verify state controller is notified communal view is hidden.
verify(mCommunalStateController).setCommunalViewShowing(false);
}
+
+ @Test
+ public void testAlphaPropagation() {
+ final float alpha = 0.8f;
+
+ // Ensure alpha setting is propagated to children.
+ when(mCommunalView.getChildCount()).thenReturn(1);
+ when(mCommunalView.getChildAt(0)).thenReturn(mChildView);
+ mController.setAlpha(alpha);
+ verify(mChildView).setAlpha(alpha);
+ verify(mCommunalView).setAlpha(alpha);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index f9e370729e23..faf968b4ff44 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -86,15 +86,14 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
@Mock
private SysuiStatusBarStateController mStatusBarStateController;
+ private TestNotificationPanelViewStateProvider mNotificationPanelViewStateProvider;
private KeyguardStatusBarView mKeyguardStatusBarView;
private KeyguardStatusBarViewController mController;
- private float mAlpha = 0.5f;
- private final KeyguardStatusBarViewController.ViewStateProvider mViewStateProvider =
- () -> new KeyguardStatusBarViewController.ViewState(mAlpha);
-
@Before
public void setup() throws Exception {
+ mNotificationPanelViewStateProvider = new TestNotificationPanelViewStateProvider();
+
MockitoAnnotations.initMocks(this);
allowTestableLooperAsMainThread();
@@ -114,7 +113,7 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
mStatusBarIconController,
new StatusBarIconController.TintedIconManager.Factory(mFeatureFlags),
mBatteryMeterViewController,
- mViewStateProvider,
+ mNotificationPanelViewStateProvider,
mKeyguardStateController,
mKeyguardBypassController,
mKeyguardUpdateMonitor,
@@ -210,7 +209,6 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
@Test
public void updateViewState_notKeyguardState_nothingUpdated() {
- mAlpha = 0.255f;
mController.onViewAttached();
updateStateToNotKeyguard();
@@ -264,8 +262,59 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
}
+ @Test
+ public void updateViewState_panelExpandedHeightZero_viewHidden() {
+ mController.onViewAttached();
+ updateStateToKeyguard();
+
+ mNotificationPanelViewStateProvider.setPanelViewExpandedHeight(0);
+
+ mController.updateViewState();
+
+ assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+ }
+
+ @Test
+ public void updateViewState_qsExpansionOne_viewHidden() {
+ mController.onViewAttached();
+ updateStateToKeyguard();
+
+ mNotificationPanelViewStateProvider.setQsExpansionFraction(1f);
+
+ mController.updateViewState();
+
+ assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+ }
+
// TODO(b/195442899): Add more tests for #updateViewState once CLs are finalized.
+ @Test
+ public void updateForHeadsUp_headsUpShouldBeVisible_viewHidden() {
+ mController.onViewAttached();
+ updateStateToKeyguard();
+ mKeyguardStatusBarView.setVisibility(View.VISIBLE);
+
+ mNotificationPanelViewStateProvider.setShouldHeadsUpBeVisible(true);
+ mController.updateForHeadsUp(/* animate= */ false);
+
+ assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+ }
+
+ @Test
+ public void updateForHeadsUp_headsUpShouldNotBeVisible_viewShown() {
+ mController.onViewAttached();
+ updateStateToKeyguard();
+
+ // Start with the opposite state.
+ mNotificationPanelViewStateProvider.setShouldHeadsUpBeVisible(true);
+ mController.updateForHeadsUp(/* animate= */ false);
+
+ mNotificationPanelViewStateProvider.setShouldHeadsUpBeVisible(false);
+ mController.updateForHeadsUp(/* animate= */ false);
+
+ assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
private void updateStateToNotKeyguard() {
updateStatusBarState(SHADE);
}
@@ -295,4 +344,41 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
callback.onFinishedGoingToSleep(0);
}
+
+ private static class TestNotificationPanelViewStateProvider
+ implements NotificationPanelViewController.NotificationPanelViewStateProvider {
+
+ TestNotificationPanelViewStateProvider() {}
+
+ private float mPanelViewExpandedHeight = 100f;
+ private float mQsExpansionFraction = 0f;
+ private boolean mShouldHeadsUpBeVisible = false;
+
+ @Override
+ public float getPanelViewExpandedHeight() {
+ return mPanelViewExpandedHeight;
+ }
+
+ @Override
+ public float getQsExpansionFraction() {
+ return mQsExpansionFraction;
+ }
+
+ @Override
+ public boolean shouldHeadsUpBeVisible() {
+ return mShouldHeadsUpBeVisible;
+ }
+
+ public void setPanelViewExpandedHeight(float panelViewExpandedHeight) {
+ this.mPanelViewExpandedHeight = panelViewExpandedHeight;
+ }
+
+ public void setQsExpansionFraction(float qsExpansionFraction) {
+ this.mQsExpansionFraction = qsExpansionFraction;
+ }
+
+ public void setShouldHeadsUpBeVisible(boolean shouldHeadsUpBeVisible) {
+ this.mShouldHeadsUpBeVisible = shouldHeadsUpBeVisible;
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index dc220362c086..38341b83446a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -29,6 +29,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
@@ -901,6 +902,14 @@ public class NotificationPanelViewTest extends SysuiTestCase {
anyBoolean(), anyBoolean(), anyInt());
}
+ @Test
+ public void testCommunalAlphaUpdate() {
+ // Verify keyguard content alpha changes are propagate. Note the actual value set is not
+ // checked since an interpolation is applied to the incoming value.
+ mNotificationPanelViewController.setKeyguardOnlyContentAlpha(0.8f);
+ verify(mCommunalHostViewController).setAlpha(anyFloat());
+ }
+
private void triggerPositionClockAndNotifications() {
mNotificationPanelViewController.closeQs();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
index 9c47f19b20c8..e6dc4db34f91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
@@ -96,6 +96,8 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
DumpManager mDumpManager;
@Mock
OverlayManagerTransaction.Builder mTransactionBuilder;
+ @Mock
+ Runnable mOnOverlaysApplied;
private ThemeOverlayApplier mManager;
private boolean mGetOverlayInfoEnabled = true;
@@ -103,7 +105,8 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
- mManager = new ThemeOverlayApplier(mOverlayManager, MoreExecutors.directExecutor(),
+ mManager = new ThemeOverlayApplier(mOverlayManager,
+ MoreExecutors.directExecutor(), MoreExecutors.directExecutor(),
LAUNCHER_PACKAGE, THEMEPICKER_PACKAGE, mDumpManager) {
@Override
protected OverlayManagerTransaction.Builder getTransactionBuilder() {
@@ -173,7 +176,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
@Test
public void allCategoriesSpecified_allEnabledExclusively() {
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
- TEST_USER_HANDLES);
+ TEST_USER_HANDLES, mOnOverlaysApplied);
verify(mOverlayManager).commit(any());
for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) {
@@ -185,7 +188,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
@Test
public void allCategoriesSpecified_sysuiCategoriesAlsoAppliedToSysuiUser() {
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
- TEST_USER_HANDLES);
+ TEST_USER_HANDLES, mOnOverlaysApplied);
for (Map.Entry<String, OverlayIdentifier> entry : ALL_CATEGORIES_MAP.entrySet()) {
if (SYSTEM_USER_CATEGORIES.contains(entry.getKey())) {
@@ -202,8 +205,9 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
public void allCategoriesSpecified_enabledForAllUserHandles() {
Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES);
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
- userHandles);
+ userHandles, mOnOverlaysApplied);
+ verify(mOnOverlaysApplied).run();
for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) {
verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
eq(TEST_USER.getIdentifier()));
@@ -219,7 +223,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES);
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
- userHandles);
+ userHandles, mOnOverlaysApplied);
for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) {
verify(mTransactionBuilder, never()).setEnabled(eq(overlayPackage), eq(true),
@@ -233,7 +237,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
mock(FabricatedOverlay.class)
};
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, pendingCreation,
- TEST_USER.getIdentifier(), TEST_USER_HANDLES);
+ TEST_USER.getIdentifier(), TEST_USER_HANDLES, mOnOverlaysApplied);
for (FabricatedOverlay overlay : pendingCreation) {
verify(mTransactionBuilder).registerFabricatedOverlay(eq(overlay));
@@ -247,7 +251,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
categoryToPackage.remove(OVERLAY_CATEGORY_ICON_ANDROID);
mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(),
- TEST_USER_HANDLES);
+ TEST_USER_HANDLES, mOnOverlaysApplied);
for (OverlayIdentifier overlayPackage : categoryToPackage.values()) {
verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
@@ -264,7 +268,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
@Test
public void zeroCategoriesSpecified_allDisabled() {
mManager.applyCurrentUserOverlays(Maps.newArrayMap(), null, TEST_USER.getIdentifier(),
- TEST_USER_HANDLES);
+ TEST_USER_HANDLES, mOnOverlaysApplied);
for (String category : THEME_CATEGORIES) {
verify(mTransactionBuilder).setEnabled(
@@ -279,7 +283,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
categoryToPackage.put("blah.category", new OverlayIdentifier("com.example.blah.category"));
mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(),
- TEST_USER_HANDLES);
+ TEST_USER_HANDLES, mOnOverlaysApplied);
verify(mTransactionBuilder, never()).setEnabled(
eq(new OverlayIdentifier("com.example.blah.category")), eq(false),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index f6a549363955..cd911cc533f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -161,7 +161,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(Map.class);
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any());
// Assert that we received the colors that we were expecting
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
@@ -183,7 +183,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
null, null), WallpaperManager.FLAG_SYSTEM);
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -204,7 +204,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(Map.class);
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any());
// Assert that we received the colors that we were expecting
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
@@ -240,7 +240,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
.isFalse();
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -270,7 +270,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
"android.theme.customization.color_both\":\"0")).isTrue();
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -300,7 +300,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
"android.theme.customization.color_both\":\"1")).isTrue();
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -327,7 +327,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index"))
.isFalse();
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -354,7 +354,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index"))
.isFalse();
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -382,7 +382,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture());
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -411,14 +411,14 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
verify(mThemeOverlayApplier, never())
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
public void onProfileAdded_setsTheme() {
mBroadcastReceiver.getValue().onReceive(null,
new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -428,7 +428,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
mBroadcastReceiver.getValue().onReceive(null,
new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -438,7 +438,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
mBroadcastReceiver.getValue().onReceive(null,
new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
verify(mThemeOverlayApplier, never())
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -450,7 +450,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
Color.valueOf(Color.BLUE), null);
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
// Regression test: null events should not reset the internal state and allow colors to be
// applied again.
@@ -458,11 +458,11 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
mColorsListener.getValue().onColorsChanged(null, WallpaperManager.FLAG_SYSTEM);
verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(),
- any());
+ any(), any());
mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.GREEN),
null, null), WallpaperManager.FLAG_SYSTEM);
verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(),
- any());
+ any(), any());
}
@Test
@@ -499,7 +499,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture());
// Colors were applied during controller initialization.
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
clearInvocations(mThemeOverlayApplier);
}
@@ -533,7 +533,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture());
// Colors were applied during controller initialization.
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
clearInvocations(mThemeOverlayApplier);
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
@@ -542,12 +542,12 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
// Defers event because we already have initial colors.
verify(mThemeOverlayApplier, never())
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
// Then event happens after setup phase is over.
when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
mDeviceProvisionedListener.getValue().onUserSetupChanged();
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -568,11 +568,11 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
Color.valueOf(Color.RED), null);
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
verify(mThemeOverlayApplier, never())
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
mWakefulnessLifecycle.dispatchFinishedGoingToSleep();
verify(mThemeOverlayApplier, never())
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -592,10 +592,10 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
Color.valueOf(Color.RED), null);
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
verify(mThemeOverlayApplier, never())
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
mWakefulnessLifecycleObserver.getValue().onFinishedGoingToSleep();
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -614,7 +614,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(Map.class);
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any());
// Assert that we received the colors that we were expecting
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
diff --git a/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java b/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
index 5f9aaaeb7325..9801407f5235 100644
--- a/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
+++ b/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
@@ -40,6 +40,7 @@ import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -47,6 +48,7 @@ import android.util.ArraySet;
import android.view.accessibility.AccessibilityManager;
import com.android.internal.R;
+import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ImageUtils;
@@ -71,6 +73,7 @@ public class PolicyWarningUIController {
@VisibleForTesting
protected static final String ACTION_DISMISS_NOTIFICATION =
TAG + ".ACTION_DISMISS_NOTIFICATION";
+ private static final String EXTRA_TIME_FOR_LOGGING = "start_time_to_log_a11y_tool";
private static final int SEND_NOTIFICATION_DELAY_HOURS = 24;
/** Current enabled accessibility services. */
@@ -179,7 +182,8 @@ public class PolicyWarningUIController {
intent.setPackage(context.getPackageName())
.setIdentifier(serviceComponentName.flattenToShortString())
.putExtra(Intent.EXTRA_COMPONENT_NAME, serviceComponentName)
- .putExtra(Intent.EXTRA_USER_ID, userId);
+ .putExtra(Intent.EXTRA_USER_ID, userId)
+ .putExtra(Intent.EXTRA_TIME, SystemClock.elapsedRealtime());
return intent;
}
@@ -214,11 +218,24 @@ public class PolicyWarningUIController {
if (TextUtils.isEmpty(action) || componentName == null) {
return;
}
+ final long startTimeMills = intent.getLongExtra(Intent.EXTRA_TIME, 0);
+ final long durationMills =
+ startTimeMills > 0 ? SystemClock.elapsedRealtime() - startTimeMills : 0;
final int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_SYSTEM);
if (ACTION_SEND_NOTIFICATION.equals(action)) {
- trySendNotification(userId, componentName);
+ if (trySendNotification(userId, componentName)) {
+ AccessibilityStatsLogUtils.logNonA11yToolServiceWarningReported(
+ componentName.getPackageName(),
+ AccessibilityStatsLogUtils.ACCESSIBILITY_PRIVACY_WARNING_STATUS_SHOWN,
+ durationMills);
+ }
} else if (ACTION_A11Y_SETTINGS.equals(action)) {
- launchSettings(userId, componentName);
+ if (tryLaunchSettings(userId, componentName)) {
+ AccessibilityStatsLogUtils.logNonA11yToolServiceWarningReported(
+ componentName.getPackageName(),
+ AccessibilityStatsLogUtils.ACCESSIBILITY_PRIVACY_WARNING_STATUS_CLICKED,
+ durationMills);
+ }
mNotificationManager.cancel(componentName.flattenToShortString(),
NOTE_A11Y_VIEW_AND_CONTROL_ACCESS);
onNotificationCanceled(userId, componentName);
@@ -240,12 +257,12 @@ public class PolicyWarningUIController {
}
}
- private void trySendNotification(int userId, ComponentName componentName) {
+ private boolean trySendNotification(int userId, ComponentName componentName) {
if (!AccessibilitySecurityPolicy.POLICY_WARNING_ENABLED) {
- return;
+ return false;
}
if (userId != mCurrentUserId) {
- return;
+ return false;
}
List<AccessibilityServiceInfo> enabledServiceInfos = getEnabledServiceInfos();
@@ -264,23 +281,27 @@ public class PolicyWarningUIController {
android.R.dimen.app_icon_size);
sendNotification(userId, componentName, displayName,
ImageUtils.buildScaledBitmap(drawable, size, size));
+ return true;
}
break;
}
}
+ return false;
}
- private void launchSettings(int userId, ComponentName componentName) {
+ private boolean tryLaunchSettings(int userId, ComponentName componentName) {
if (userId != mCurrentUserId) {
- return;
+ return false;
}
final Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.putExtra(Intent.EXTRA_COMPONENT_NAME, componentName.flattenToShortString());
+ intent.putExtra(EXTRA_TIME_FOR_LOGGING, SystemClock.elapsedRealtime());
final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(
mContext.getDisplayId()).toBundle();
mContext.startActivityAsUser(intent, bundle, UserHandle.of(userId));
mContext.getSystemService(StatusBarManager.class).collapsePanels();
+ return true;
}
protected void onNotificationCanceled(int userId, ComponentName componentName) {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index c87a6fa0b98b..6505c20e0d0f 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -207,10 +207,3 @@ prebuilt_etc {
name: "protolog.conf.json.gz",
src: ":services.core.json.gz",
}
-
-filegroup {
- name: "services.core-sources-deviceconfig-interface",
- srcs: [
- "java/com/android/server/utils/DeviceConfigInterface.java",
- ],
-}
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 449f02ea5224..3c6b6826433a 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -492,7 +492,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
for (int uid : uidsToRemove) {
FrameworkStatsLog.write(FrameworkStatsLog.ISOLATED_UID_CHANGED, -1, uid,
FrameworkStatsLog.ISOLATED_UID_CHANGED__EVENT__REMOVED);
- mStats.removeIsolatedUidLocked(uid, SystemClock.elapsedRealtime(),
+ mStats.maybeRemoveIsolatedUidLocked(uid, SystemClock.elapsedRealtime(),
SystemClock.uptimeMillis());
}
mStats.clearPendingRemovedUidsLocked();
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index fa7eae3b2231..256c4721c543 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -594,7 +594,8 @@ class UserController implements Handler.Callback {
final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
t.traceBegin("UM.onBeforeUnlockUser-" + userId);
- mInjector.getUserManager().onBeforeUnlockUser(userId);
+ final ArraySet<String> reconciledPackages =
+ mInjector.getUserManager().onBeforeUnlockUser(userId);
t.traceEnd();
synchronized (mLock) {
// Do not proceed if unexpected state
@@ -603,6 +604,9 @@ class UserController implements Handler.Callback {
}
}
mInjector.getUserManagerInternal().setUserState(userId, uss.state);
+ t.traceBegin("UM.onUserStateRunningUnlocking-" + userId);
+ mInjector.getUserManager().onUserStateRunningUnlocking(userId, reconciledPackages);
+ t.traceEnd();
uss.mUnlockProgress.setProgress(20);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index dd620ac553cc..f5d29fc2600c 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -5271,6 +5271,10 @@ public class AudioService extends IAudioService.Stub
// TODO investigate internal users due to deprecation of SDK API
/** @see AudioManager#setBluetoothA2dpOn(boolean) */
public void setBluetoothA2dpOn(boolean on) {
+ if (!checkAudioSettingsPermission("setBluetoothA2dpOn()")) {
+ return;
+ }
+
// for logging only
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
@@ -5296,6 +5300,10 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#startBluetoothSco() */
public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
+ if (!checkAudioSettingsPermission("startBluetoothSco()")) {
+ return;
+ }
+
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
final int scoAudioMode =
@@ -5318,6 +5326,10 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#startBluetoothScoVirtualCall() */
public void startBluetoothScoVirtualCall(IBinder cb) {
+ if (!checkAudioSettingsPermission("startBluetoothScoVirtualCall()")) {
+ return;
+ }
+
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
final String eventSource = new StringBuilder("startBluetoothScoVirtualCall()")
diff --git a/services/core/java/com/android/server/audio/RotationHelper.java b/services/core/java/com/android/server/audio/RotationHelper.java
index ad7216600e61..872b1feb2d72 100644
--- a/services/core/java/com/android/server/audio/RotationHelper.java
+++ b/services/core/java/com/android/server/audio/RotationHelper.java
@@ -21,20 +21,26 @@ import android.hardware.display.DisplayManager;
import android.media.AudioSystem;
import android.os.Handler;
import android.util.Log;
+import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;
/**
* Class to handle device rotation events for AudioService, and forward device rotation
- * to the audio HALs through AudioSystem.
+ * and current active ID to the audio HALs through AudioSystem.
*
* The role of this class is to monitor device orientation changes, and upon rotation,
* verify the UI orientation. In case of a change, send the new orientation, in increments
* of 90deg, through AudioSystem.
*
+ * Another role of this class is to track current active display ID changes. In case of a
+ * change, send the new active display ID through AudioSystem.
+ *
* Note that even though we're responding to device orientation events, we always
* query the display rotation so audio stays in sync with video/dialogs. This is
* done with .getDefaultDisplay().getRotation() from WINDOW_SERVICE.
+ *
+ * We also monitor current display ID and audio is able to know which display is active.
*/
class RotationHelper {
@@ -43,7 +49,9 @@ class RotationHelper {
private static AudioDisplayListener sDisplayListener;
private static final Object sRotationLock = new Object();
+ private static final Object sActiveDisplayLock = new Object();
private static int sDeviceRotation = Surface.ROTATION_0; // R/W synchronized on sRotationLock
+ private static int sDisplayId = Display.DEFAULT_DISPLAY; // synchronized on sActiveDisplayLock
private static Context sContext;
private static Handler sHandler;
@@ -112,6 +120,18 @@ class RotationHelper {
}
/**
+ * Query current display active id and publish the change if any.
+ */
+ static void updateActiveDisplayId(int displayId) {
+ synchronized (sActiveDisplayLock) {
+ if (displayId != Display.DEFAULT_DISPLAY && sDisplayId != displayId) {
+ sDisplayId = displayId;
+ AudioSystem.setParameters("active_displayId=" + sDisplayId);
+ }
+ }
+ }
+
+ /**
* Uses android.hardware.display.DisplayManager.DisplayListener
*/
final static class AudioDisplayListener implements DisplayManager.DisplayListener {
@@ -126,6 +146,7 @@ class RotationHelper {
@Override
public void onDisplayChanged(int displayId) {
+ updateActiveDisplayId(displayId);
updateOrientation();
}
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index a25cfd8f3ba4..e16a241e6572 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -41,6 +41,7 @@ import android.os.Message;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.DeviceConfig;
+import android.provider.DeviceConfigInterface;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.IndentingPrintWriter;
@@ -61,7 +62,6 @@ import com.android.server.display.utils.AmbientFilterFactory;
import com.android.server.sensors.SensorManagerInternal;
import com.android.server.sensors.SensorManagerInternal.ProximityActiveListener;
import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.utils.DeviceConfigInterface;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 557fa8944445..df372b1459af 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -290,7 +290,8 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
combined.getValues(augmentStart, augmentEnd, entry);
}
- final long rawBytes = entry.rxBytes + entry.txBytes;
+ final long rawBytes = (entry.rxBytes + entry.txBytes) == 0 ? 1 :
+ (entry.rxBytes + entry.txBytes);
final long rawRxBytes = entry.rxBytes == 0 ? 1 : entry.rxBytes;
final long rawTxBytes = entry.txBytes == 0 ? 1 : entry.txBytes;
final long targetBytes = augmentPlan.getDataUsageBytes();
diff --git a/services/core/java/com/android/server/pm/HandlerParams.java b/services/core/java/com/android/server/pm/HandlerParams.java
index b8c2eb87e0c5..ab24ee5ccfa2 100644
--- a/services/core/java/com/android/server/pm/HandlerParams.java
+++ b/services/core/java/com/android/server/pm/HandlerParams.java
@@ -16,20 +16,35 @@
package com.android.server.pm;
+import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
+
+import android.annotation.NonNull;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInfoLite;
+import android.content.pm.PackageManager;
import android.os.UserHandle;
+import android.util.Pair;
import android.util.Slog;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.TAG;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
abstract class HandlerParams {
/** User handle for the user requesting the information or installation. */
private final UserHandle mUser;
String mTraceMethod;
int mTraceCookie;
+ @NonNull
+ final PackageManagerService mPm;
- HandlerParams(UserHandle user) {
+ // TODO(b/198166813): remove PMS dependency
+ HandlerParams(UserHandle user, PackageManagerService pm) {
mUser = user;
+ mPm = pm;
}
UserHandle getUser() {
@@ -54,4 +69,135 @@ abstract class HandlerParams {
abstract void handleStartCopy();
abstract void handleReturnCode();
+
+ Pair<Integer, String> verifyReplacingVersionCode(PackageInfoLite pkgLite,
+ long requiredInstalledVersionCode, int installFlags) {
+ if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
+ return verifyReplacingVersionCodeForApex(
+ pkgLite, requiredInstalledVersionCode, installFlags);
+ }
+
+ String packageName = pkgLite.packageName;
+ synchronized (mPm.mLock) {
+ // Package which currently owns the data that the new package will own if installed.
+ // If an app is uninstalled while keeping data (e.g. adb uninstall -k), installedPkg
+ // will be null whereas dataOwnerPkg will contain information about the package
+ // which was uninstalled while keeping its data.
+ AndroidPackage dataOwnerPkg = mPm.mPackages.get(packageName);
+ if (dataOwnerPkg == null) {
+ PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
+ if (ps != null) {
+ dataOwnerPkg = ps.pkg;
+ }
+ }
+
+ if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) {
+ if (dataOwnerPkg == null) {
+ String errorMsg = "Required installed version code was "
+ + requiredInstalledVersionCode
+ + " but package is not installed";
+ Slog.w(TAG, errorMsg);
+ return Pair.create(
+ PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
+ }
+
+ if (dataOwnerPkg.getLongVersionCode() != requiredInstalledVersionCode) {
+ String errorMsg = "Required installed version code was "
+ + requiredInstalledVersionCode
+ + " but actual installed version is "
+ + dataOwnerPkg.getLongVersionCode();
+ Slog.w(TAG, errorMsg);
+ return Pair.create(
+ PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
+ }
+ }
+
+ if (dataOwnerPkg != null) {
+ if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
+ dataOwnerPkg.isDebuggable())) {
+ try {
+ checkDowngrade(dataOwnerPkg, pkgLite);
+ } catch (PackageManagerException e) {
+ String errorMsg = "Downgrade detected: " + e.getMessage();
+ Slog.w(TAG, errorMsg);
+ return Pair.create(
+ PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg);
+ }
+ }
+ }
+ }
+ return Pair.create(PackageManager.INSTALL_SUCCEEDED, null);
+ }
+
+ private Pair<Integer, String> verifyReplacingVersionCodeForApex(PackageInfoLite pkgLite,
+ long requiredInstalledVersionCode, int installFlags) {
+ String packageName = pkgLite.packageName;
+
+ final PackageInfo activePackage = mPm.mApexManager.getPackageInfo(packageName,
+ ApexManager.MATCH_ACTIVE_PACKAGE);
+ if (activePackage == null) {
+ String errorMsg = "Attempting to install new APEX package " + packageName;
+ Slog.w(TAG, errorMsg);
+ return Pair.create(PackageManager.INSTALL_FAILED_PACKAGE_CHANGED, errorMsg);
+ }
+
+ final long activeVersion = activePackage.getLongVersionCode();
+ if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST
+ && activeVersion != requiredInstalledVersionCode) {
+ String errorMsg = "Installed version of APEX package " + packageName
+ + " does not match required. Active version: " + activeVersion
+ + " required: " + requiredInstalledVersionCode;
+ Slog.w(TAG, errorMsg);
+ return Pair.create(PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
+ }
+
+ final boolean isAppDebuggable = (activePackage.applicationInfo.flags
+ & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+ final long newVersionCode = pkgLite.getLongVersionCode();
+ if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags, isAppDebuggable)
+ && newVersionCode < activeVersion) {
+ String errorMsg = "Downgrade of APEX package " + packageName
+ + " is not allowed. Active version: " + activeVersion
+ + " attempted: " + newVersionCode;
+ Slog.w(TAG, errorMsg);
+ return Pair.create(PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg);
+ }
+
+ return Pair.create(PackageManager.INSTALL_SUCCEEDED, null);
+ }
+
+ /**
+ * Check and throw if the given before/after packages would be considered a
+ * downgrade.
+ */
+ private static void checkDowngrade(AndroidPackage before, PackageInfoLite after)
+ throws PackageManagerException {
+ if (after.getLongVersionCode() < before.getLongVersionCode()) {
+ throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
+ "Update version code " + after.versionCode + " is older than current "
+ + before.getLongVersionCode());
+ } else if (after.getLongVersionCode() == before.getLongVersionCode()) {
+ if (after.baseRevisionCode < before.getBaseRevisionCode()) {
+ throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
+ "Update base revision code " + after.baseRevisionCode
+ + " is older than current " + before.getBaseRevisionCode());
+ }
+
+ if (!ArrayUtils.isEmpty(after.splitNames)) {
+ for (int i = 0; i < after.splitNames.length; i++) {
+ final String splitName = after.splitNames[i];
+ final int j = ArrayUtils.indexOf(before.getSplitNames(), splitName);
+ if (j != -1) {
+ if (after.splitRevisionCodes[i] < before.getSplitRevisionCodes()[j]) {
+ throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
+ "Update split " + splitName + " revision code "
+ + after.splitRevisionCodes[i]
+ + " is older than current "
+ + before.getSplitRevisionCodes()[j]);
+ }
+ }
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
new file mode 100644
index 000000000000..d600ae52900d
--- /dev/null
+++ b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
@@ -0,0 +1,1325 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
+import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
+import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.os.incremental.IncrementalManager.isIncrementalPath;
+import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
+import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
+import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
+
+import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION;
+import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
+import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
+import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
+import static com.android.server.pm.PackageManagerService.DEBUG_VERIFY;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_APK_IN_APEX;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_PRIVILEGED;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM;
+import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX;
+import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN;
+import static com.android.server.pm.PackageManagerService.SCAN_UPDATE_SIGNATURE;
+import static com.android.server.pm.PackageManagerService.TAG;
+import static com.android.server.pm.PackageManagerServiceUtils.decompressFile;
+import static com.android.server.pm.PackageManagerServiceUtils.getCompressedFiles;
+import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
+import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+import static com.android.server.pm.PackageManagerServiceUtils.makeDirRecursive;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.SigningDetails;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
+import android.os.Environment;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.system.ErrnoException;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.F2fsUtils;
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.security.VerityUtils;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.EventLogTags;
+import com.android.server.pm.parsing.PackageCacher;
+import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.utils.WatchedArrayMap;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.DigestException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Part of PackageManagerService that handles init and system packages. This class still needs
+ * further cleanup and eventually all the installation/scanning related logic will go to another
+ * class.
+ */
+public class InitAndSystemPackageHelper {
+ final PackageManagerService mPm;
+
+ // TODO(b/198166813): remove PMS dependency
+ public InitAndSystemPackageHelper(PackageManagerService pm) {
+ mPm = pm;
+ }
+
+ /**
+ * First part of init dir scanning
+ */
+ // TODO(b/197876467): consolidate this with cleanupSystemPackagesAndInstallStubs
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ public void scanSystemDirs(List<ScanPartition> dirsToScanAsSystem,
+ boolean isUpgrade, PackageParser2 packageParser,
+ ExecutorService executorService, AndroidPackage platformPackage,
+ boolean isPreNMR1Upgrade, int systemParseFlags, int systemScanFlags) {
+ File frameworkDir = new File(Environment.getRootDirectory(), "framework");
+
+ // Collect vendor/product/system_ext overlay packages. (Do this before scanning
+ // any apps.)
+ // For security and version matching reason, only consider overlay packages if they
+ // reside in the right directory.
+ for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) {
+ final ScanPartition partition = dirsToScanAsSystem.get(i);
+ if (partition.getOverlayFolder() == null) {
+ continue;
+ }
+ scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags,
+ systemScanFlags | partition.scanFlag, 0,
+ packageParser, executorService, platformPackage, isUpgrade,
+ isPreNMR1Upgrade);
+ }
+
+ scanDirTracedLI(frameworkDir, systemParseFlags,
+ systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
+ packageParser, executorService, platformPackage, isUpgrade, isPreNMR1Upgrade);
+ if (!mPm.mPackages.containsKey("android")) {
+ throw new IllegalStateException(
+ "Failed to load frameworks package; check log for warnings");
+ }
+
+ for (int i = 0, size = dirsToScanAsSystem.size(); i < size; i++) {
+ final ScanPartition partition = dirsToScanAsSystem.get(i);
+ if (partition.getPrivAppFolder() != null) {
+ scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags,
+ systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
+ packageParser, executorService, platformPackage, isUpgrade,
+ isPreNMR1Upgrade);
+ }
+ scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
+ systemScanFlags | partition.scanFlag, 0,
+ packageParser, executorService, platformPackage, isUpgrade,
+ isPreNMR1Upgrade);
+ }
+ }
+
+ /**
+ * Second part of init dir scanning
+ */
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ public void cleanupSystemPackagesAndInstallStubs(List<ScanPartition> dirsToScanAsSystem,
+ boolean isUpgrade, PackageParser2 packageParser,
+ ExecutorService executorService, boolean onlyCore,
+ WatchedArrayMap<String, PackageSetting> packageSettings,
+ long startTime, File appInstallDir, AndroidPackage platformPackage,
+ boolean isPreNMR1Upgrade, int scanFlags, int systemParseFlags, int systemScanFlags,
+ int[] userIds) {
+ // Prune any system packages that no longer exist.
+ final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
+ // Stub packages must either be replaced with full versions in the /data
+ // partition or be disabled.
+ final List<String> stubSystemApps = new ArrayList<>();
+
+ if (!onlyCore) {
+ // do this first before mucking with mPackages for the "expecting better" case
+ final int numPackages = mPm.mPackages.size();
+ for (int index = 0; index < numPackages; index++) {
+ final AndroidPackage pkg = mPm.mPackages.valueAt(index);
+ if (pkg.isStub()) {
+ stubSystemApps.add(pkg.getPackageName());
+ }
+ }
+
+ // Iterates PackageSettings in reversed order because the item could be removed
+ // during the iteration.
+ for (int index = packageSettings.size() - 1; index >= 0; index--) {
+ final PackageSetting ps = packageSettings.valueAt(index);
+
+ /*
+ * If this is not a system app, it can't be a
+ * disable system app.
+ */
+ if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ continue;
+ }
+
+ /*
+ * If the package is scanned, it's not erased.
+ */
+ final AndroidPackage scannedPkg = mPm.mPackages.get(ps.name);
+ if (scannedPkg != null) {
+ /*
+ * If the system app is both scanned and in the
+ * disabled packages list, then it must have been
+ * added via OTA. Remove it from the currently
+ * scanned package so the previously user-installed
+ * application can be scanned.
+ */
+ if (mPm.mSettings.isDisabledSystemPackageLPr(ps.name)) {
+ logCriticalInfo(Log.WARN,
+ "Expecting better updated system app for " + ps.name
+ + "; removing system app. Last known"
+ + " codePath=" + ps.getPathString()
+ + ", versionCode=" + ps.versionCode
+ + "; scanned versionCode="
+ + scannedPkg.getLongVersionCode());
+ mPm.removePackageLI(scannedPkg, true);
+ mPm.mExpectingBetter.put(ps.name, ps.getPath());
+ }
+
+ continue;
+ }
+
+ if (!mPm.mSettings.isDisabledSystemPackageLPr(ps.name)) {
+ logCriticalInfo(Log.WARN, "System package " + ps.name
+ + " no longer exists; its data will be wiped");
+ mPm.removePackageDataLIF(ps, userIds, null, 0, false);
+ } else {
+ // we still have a disabled system package, but, it still might have
+ // been removed. check the code path still exists and check there's
+ // still a package. the latter can happen if an OTA keeps the same
+ // code path, but, changes the package name.
+ final PackageSetting disabledPs =
+ mPm.mSettings.getDisabledSystemPkgLPr(ps.name);
+ if (disabledPs.getPath() == null || !disabledPs.getPath().exists()
+ || disabledPs.pkg == null) {
+ possiblyDeletedUpdatedSystemApps.add(ps.name);
+ } else {
+ // We're expecting that the system app should remain disabled, but add
+ // it to expecting better to recover in case the data version cannot
+ // be scanned.
+ // TODO(b/197869066): mExpectingBetter should be able to pulled out into
+ // this class and used only by the PMS initialization
+ mPm.mExpectingBetter.put(disabledPs.name, disabledPs.getPath());
+ }
+ }
+ }
+ }
+
+ final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
+
+ // Remove any shared userIDs that have no associated packages
+ mPm.mSettings.pruneSharedUsersLPw();
+ final long systemScanTime = SystemClock.uptimeMillis() - startTime;
+ final int systemPackagesCount = mPm.mPackages.size();
+ Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
+ + " ms, packageCount: " + systemPackagesCount
+ + " , timePerPackage: "
+ + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
+ + " , cached: " + cachedSystemApps);
+ if (isUpgrade && systemPackagesCount > 0) {
+ //CHECKSTYLE:OFF IndentationCheck
+ FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+ BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
+ systemScanTime / systemPackagesCount);
+ //CHECKSTYLE:ON IndentationCheck
+ }
+ if (!onlyCore) {
+ EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
+ SystemClock.uptimeMillis());
+ scanDirTracedLI(appInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
+ packageParser, executorService, platformPackage, isUpgrade,
+ isPreNMR1Upgrade);
+
+ }
+
+ List<Runnable> unfinishedTasks = executorService.shutdownNow();
+ if (!unfinishedTasks.isEmpty()) {
+ throw new IllegalStateException("Not all tasks finished before calling close: "
+ + unfinishedTasks);
+ }
+
+ if (!onlyCore) {
+ // Remove disable package settings for updated system apps that were
+ // removed via an OTA. If the update is no longer present, remove the
+ // app completely. Otherwise, revoke their system privileges.
+ for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
+ final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
+ final AndroidPackage pkg = mPm.mPackages.get(packageName);
+ final String msg;
+
+ // remove from the disabled system list; do this first so any future
+ // scans of this package are performed without this state
+ mPm.mSettings.removeDisabledSystemPackageLPw(packageName);
+
+ if (pkg == null) {
+ // should have found an update, but, we didn't; remove everything
+ msg = "Updated system package " + packageName
+ + " no longer exists; removing its data";
+ // Actual deletion of code and data will be handled by later
+ // reconciliation step
+ } else {
+ // found an update; revoke system privileges
+ msg = "Updated system package " + packageName
+ + " no longer exists; rescanning package on data";
+
+ // NOTE: We don't do anything special if a stub is removed from the
+ // system image. But, if we were [like removing the uncompressed
+ // version from the /data partition], this is where it'd be done.
+
+ // remove the package from the system and re-scan it without any
+ // special privileges
+ mPm.removePackageLI(pkg, true);
+ try {
+ final File codePath = new File(pkg.getPath());
+ mPm.scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
+ } catch (PackageManagerException e) {
+ Slog.e(TAG, "Failed to parse updated, ex-system package: "
+ + e.getMessage());
+ }
+ }
+
+ // one final check. if we still have a package setting [ie. it was
+ // previously scanned and known to the system], but, we don't have
+ // a package [ie. there was an error scanning it from the /data
+ // partition], completely remove the package data.
+ final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
+ if (ps != null && mPm.mPackages.get(packageName) == null) {
+ mPm.removePackageDataLIF(ps, userIds, null, 0, false);
+
+ }
+ logCriticalInfo(Log.WARN, msg);
+ }
+
+ /*
+ * Make sure all system apps that we expected to appear on
+ * the userdata partition actually showed up. If they never
+ * appeared, crawl back and revive the system version.
+ */
+ for (int i = 0; i < mPm.mExpectingBetter.size(); i++) {
+ final String packageName = mPm.mExpectingBetter.keyAt(i);
+ if (!mPm.mPackages.containsKey(packageName)) {
+ final File scanFile = mPm.mExpectingBetter.valueAt(i);
+
+ logCriticalInfo(Log.WARN, "Expected better " + packageName
+ + " but never showed up; reverting to system");
+
+ @ParsingPackageUtils.ParseFlags int reparseFlags = 0;
+ @PackageManagerService.ScanFlags int rescanFlags = 0;
+ for (int i1 = dirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
+ final ScanPartition partition = dirsToScanAsSystem.get(i1);
+ if (partition.containsPrivApp(scanFile)) {
+ reparseFlags = systemParseFlags;
+ rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED
+ | partition.scanFlag;
+ break;
+ }
+ if (partition.containsApp(scanFile)) {
+ reparseFlags = systemParseFlags;
+ rescanFlags = systemScanFlags | partition.scanFlag;
+ break;
+ }
+ }
+ if (rescanFlags == 0) {
+ Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
+ continue;
+ }
+ mPm.mSettings.enableSystemPackageLPw(packageName);
+
+ try {
+ final AndroidPackage newPkg = mPm.scanPackageTracedLI(
+ scanFile, reparseFlags, rescanFlags, 0, null);
+ // We rescanned a stub, add it to the list of stubbed system packages
+ if (newPkg.isStub()) {
+ stubSystemApps.add(packageName);
+ }
+ } catch (PackageManagerException e) {
+ Slog.e(TAG, "Failed to parse original system package: "
+ + e.getMessage());
+ }
+ }
+ }
+
+ // Uncompress and install any stubbed system applications.
+ // This must be done last to ensure all stubs are replaced or disabled.
+ installSystemStubPackages(stubSystemApps, scanFlags);
+
+ final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
+ - cachedSystemApps;
+
+ final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
+ final int dataPackagesCount = mPm.mPackages.size() - systemPackagesCount;
+ Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
+ + " ms, packageCount: " + dataPackagesCount
+ + " , timePerPackage: "
+ + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
+ + " , cached: " + cachedNonSystemApps);
+ if (isUpgrade && dataPackagesCount > 0) {
+ //CHECKSTYLE:OFF IndentationCheck
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+ BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
+ dataScanTime / dataPackagesCount);
+ //CHECKSTYLE:OFF IndentationCheck
+ }
+ }
+ mPm.mExpectingBetter.clear();
+
+ mPm.mSettings.pruneRenamedPackagesLPw();
+ }
+
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
+ long currentTime, PackageParser2 packageParser, ExecutorService executorService,
+ AndroidPackage platformPackage, boolean isUpgrade, boolean isPreNMR1Upgrade) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
+ try {
+ scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService,
+ platformPackage, isUpgrade, isPreNMR1Upgrade);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
+ PackageParser2 packageParser, ExecutorService executorService,
+ AndroidPackage platformPackage, boolean isUpgrade, boolean isPreNMR1Upgrade) {
+ final File[] files = scanDir.listFiles();
+ if (ArrayUtils.isEmpty(files)) {
+ Log.d(TAG, "No files in app dir " + scanDir);
+ return;
+ }
+
+ if (DEBUG_PACKAGE_SCANNING) {
+ Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
+ + " flags=0x" + Integer.toHexString(parseFlags));
+ }
+
+ ParallelPackageParser parallelPackageParser =
+ new ParallelPackageParser(packageParser, executorService);
+
+ // Submit files for parsing in parallel
+ int fileCount = 0;
+ for (File file : files) {
+ final boolean isPackage = (isApkFile(file) || file.isDirectory())
+ && !PackageInstallerService.isStageName(file.getName());
+ if (!isPackage) {
+ // Ignore entries which are not packages
+ continue;
+ }
+ parallelPackageParser.submit(file, parseFlags);
+ fileCount++;
+ }
+
+ // Process results one by one
+ for (; fileCount > 0; fileCount--) {
+ ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
+ Throwable throwable = parseResult.throwable;
+ int errorCode = PackageManager.INSTALL_SUCCEEDED;
+ String errorMsg = null;
+
+ if (throwable == null) {
+ // TODO(b/194319951): move lower in the scan chain
+ // Static shared libraries have synthetic package names
+ if (parseResult.parsedPackage.isStaticSharedLibrary()) {
+ PackageManagerService.renameStaticSharedLibraryPackage(
+ parseResult.parsedPackage);
+ }
+ try {
+ addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
+ currentTime, null, platformPackage, isUpgrade,
+ isPreNMR1Upgrade);
+ } catch (PackageManagerException e) {
+ errorCode = e.error;
+ errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage();
+ Slog.w(TAG, errorMsg);
+ }
+ } else if (throwable instanceof PackageManagerException) {
+ PackageManagerException e = (PackageManagerException) throwable;
+ errorCode = e.error;
+ errorMsg = "Failed to parse " + parseResult.scanFile + ": " + e.getMessage();
+ Slog.w(TAG, errorMsg);
+ } else {
+ throw new IllegalStateException("Unexpected exception occurred while parsing "
+ + parseResult.scanFile, throwable);
+ }
+
+ if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) {
+ mPm.mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath(), errorMsg);
+ }
+
+ // Delete invalid userdata apps
+ if ((scanFlags & SCAN_AS_SYSTEM) == 0
+ && errorCode != PackageManager.INSTALL_SUCCEEDED) {
+ logCriticalInfo(Log.WARN,
+ "Deleting invalid package at " + parseResult.scanFile);
+ mPm.removeCodePathLI(parseResult.scanFile);
+ }
+ }
+ }
+
+ /**
+ * Uncompress and install stub applications.
+ * <p>In order to save space on the system partition, some applications are shipped in a
+ * compressed form. In addition the compressed bits for the full application, the
+ * system image contains a tiny stub comprised of only the Android manifest.
+ * <p>During the first boot, attempt to uncompress and install the full application. If
+ * the application can't be installed for any reason, disable the stub and prevent
+ * uncompressing the full application during future boots.
+ * <p>In order to forcefully attempt an installation of a full application, go to app
+ * settings and enable the application.
+ */
+ @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
+ private void installSystemStubPackages(@NonNull List<String> systemStubPackageNames,
+ @PackageManagerService.ScanFlags int scanFlags) {
+ for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
+ final String packageName = systemStubPackageNames.get(i);
+ // skip if the system package is already disabled
+ if (mPm.mSettings.isDisabledSystemPackageLPr(packageName)) {
+ systemStubPackageNames.remove(i);
+ continue;
+ }
+ // skip if the package isn't installed (?!); this should never happen
+ final AndroidPackage pkg = mPm.mPackages.get(packageName);
+ if (pkg == null) {
+ systemStubPackageNames.remove(i);
+ continue;
+ }
+ // skip if the package has been disabled by the user
+ final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
+ if (ps != null) {
+ final int enabledState = ps.getEnabled(UserHandle.USER_SYSTEM);
+ if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
+ systemStubPackageNames.remove(i);
+ continue;
+ }
+ }
+
+ // install the package to replace the stub on /system
+ try {
+ installStubPackageLI(pkg, 0, scanFlags);
+ ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+ UserHandle.USER_SYSTEM, "android");
+ systemStubPackageNames.remove(i);
+ } catch (PackageManagerException e) {
+ Slog.e(TAG, "Failed to parse uncompressed system package: " + e.getMessage());
+ }
+
+ // any failed attempt to install the package will be cleaned up later
+ }
+
+ // disable any stub still left; these failed to install the full application
+ for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
+ final String pkgName = systemStubPackageNames.get(i);
+ final PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName);
+ ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ UserHandle.USER_SYSTEM, "android");
+ logCriticalInfo(Log.ERROR, "Stub disabled; pkg: " + pkgName);
+ }
+ }
+
+ /**
+ * Extract, install and enable a stub package.
+ * <p>If the compressed file can not be extracted / installed for any reason, the stub
+ * APK will be installed and the package will be disabled. To recover from this situation,
+ * the user will need to go into system settings and re-enable the package.
+ */
+ @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
+ public boolean enableCompressedPackage(AndroidPackage stubPkg,
+ @NonNull PackageSetting stubPkgSetting, int defParseFlags,
+ List<ScanPartition> dirsToScanAsSystem) {
+ final int parseFlags = defParseFlags | ParsingPackageUtils.PARSE_CHATTY
+ | ParsingPackageUtils.PARSE_ENFORCE_CODE;
+ synchronized (mPm.mInstallLock) {
+ final AndroidPackage pkg;
+ try (PackageFreezer freezer =
+ mPm.freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
+ pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
+ synchronized (mPm.mLock) {
+ mPm.prepareAppDataAfterInstallLIF(pkg);
+ try {
+ mPm.updateSharedLibrariesLocked(pkg, stubPkgSetting, null, null,
+ Collections.unmodifiableMap(mPm.mPackages));
+ } catch (PackageManagerException e) {
+ Slog.w(TAG, "updateAllSharedLibrariesLPw failed: ", e);
+ }
+ mPm.mPermissionManager.onPackageInstalled(pkg,
+ PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
+ UserHandle.USER_ALL);
+ mPm.writeSettingsLPrTEMP();
+ }
+ } catch (PackageManagerException e) {
+ // Whoops! Something went very wrong; roll back to the stub and disable the package
+ try (PackageFreezer freezer =
+ mPm.freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
+ synchronized (mPm.mLock) {
+ // NOTE: Ensure the system package is enabled; even for a compressed stub.
+ // If we don't, installing the system package fails during scan
+ enableSystemPackageLPw(stubPkg);
+ }
+ installPackageFromSystemLIF(stubPkg.getPath(),
+ mPm.mUserManager.getUserIds() /*allUserHandles*/,
+ null /*origUserHandles*/,
+ true /*writeSettings*/, defParseFlags, dirsToScanAsSystem);
+ } catch (PackageManagerException pme) {
+ // Serious WTF; we have to be able to install the stub
+ Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
+ pme);
+ } finally {
+ // Disable the package; the stub by itself is not runnable
+ synchronized (mPm.mLock) {
+ final PackageSetting stubPs = mPm.mSettings.getPackageLPr(
+ stubPkg.getPackageName());
+ if (stubPs != null) {
+ stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
+ UserHandle.USER_SYSTEM, "android");
+ }
+ mPm.writeSettingsLPrTEMP();
+ }
+ }
+ return false;
+ }
+ mPm.clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
+ | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+ mPm.getDexManager().notifyPackageUpdated(pkg.getPackageName(),
+ pkg.getBaseApkPath(), pkg.getSplitCodePaths());
+ }
+ return true;
+ }
+
+ @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
+ private AndroidPackage installStubPackageLI(AndroidPackage stubPkg,
+ @ParsingPackageUtils.ParseFlags int parseFlags,
+ @PackageManagerService.ScanFlags int scanFlags)
+ throws PackageManagerException {
+ if (DEBUG_COMPRESSION) {
+ Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.getPackageName());
+ }
+ // uncompress the binary to its eventual destination on /data
+ final File scanFile = decompressPackage(stubPkg.getPackageName(), stubPkg.getPath());
+ if (scanFile == null) {
+ throw new PackageManagerException(
+ "Unable to decompress stub at " + stubPkg.getPath());
+ }
+ synchronized (mPm.mLock) {
+ mPm.mSettings.disableSystemPackageLPw(stubPkg.getPackageName(), true /*replaced*/);
+ }
+ mPm.removePackageLI(stubPkg, true /*chatty*/);
+ try {
+ return mPm.scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
+ } catch (PackageManagerException e) {
+ Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
+ e);
+ // Remove the failed install
+ mPm.removeCodePathLI(scanFile);
+ throw e;
+ }
+ }
+
+ /**
+ * Decompresses the given package on the system image onto
+ * the /data partition.
+ * @return The directory the package was decompressed into. Otherwise, {@code null}.
+ */
+ @GuardedBy("mPm.mInstallLock")
+ private File decompressPackage(String packageName, String codePath) {
+ final File[] compressedFiles = getCompressedFiles(codePath);
+ if (compressedFiles == null || compressedFiles.length == 0) {
+ if (DEBUG_COMPRESSION) {
+ Slog.i(TAG, "No files to decompress: " + codePath);
+ }
+ return null;
+ }
+ final File dstCodePath =
+ PackageManagerService.getNextCodePath(Environment.getDataAppDirectory(null),
+ packageName);
+ int ret = PackageManager.INSTALL_SUCCEEDED;
+ try {
+ makeDirRecursive(dstCodePath, 0755);
+ for (File srcFile : compressedFiles) {
+ final String srcFileName = srcFile.getName();
+ final String dstFileName = srcFileName.substring(
+ 0, srcFileName.length() - COMPRESSED_EXTENSION.length());
+ final File dstFile = new File(dstCodePath, dstFileName);
+ ret = decompressFile(srcFile, dstFile);
+ if (ret != PackageManager.INSTALL_SUCCEEDED) {
+ logCriticalInfo(Log.ERROR, "Failed to decompress"
+ + "; pkg: " + packageName
+ + ", file: " + dstFileName);
+ break;
+ }
+ }
+ } catch (ErrnoException e) {
+ logCriticalInfo(Log.ERROR, "Failed to decompress"
+ + "; pkg: " + packageName
+ + ", err: " + e.errno);
+ }
+ if (ret == PackageManager.INSTALL_SUCCEEDED) {
+ final File libraryRoot = new File(dstCodePath, LIB_DIR_NAME);
+ NativeLibraryHelper.Handle handle = null;
+ try {
+ handle = NativeLibraryHelper.Handle.create(dstCodePath);
+ ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
+ null /*abiOverride*/, false /*isIncremental*/);
+ } catch (IOException e) {
+ logCriticalInfo(Log.ERROR, "Failed to extract native libraries"
+ + "; pkg: " + packageName);
+ ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ } finally {
+ IoUtils.closeQuietly(handle);
+ }
+ }
+ if (ret == PackageManager.INSTALL_SUCCEEDED) {
+ // NOTE: During boot, we have to delay releasing cblocks for no other reason than
+ // we cannot retrieve the setting {@link Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL}.
+ // When we no longer need to read that setting, cblock release can occur always
+ // occur here directly
+ if (!mPm.mSystemReady) {
+ if (mPm.mReleaseOnSystemReady == null) {
+ mPm.mReleaseOnSystemReady = new ArrayList<>();
+ }
+ mPm.mReleaseOnSystemReady.add(dstCodePath);
+ } else {
+ final ContentResolver resolver = mPm.mContext.getContentResolver();
+ F2fsUtils.releaseCompressedBlocks(resolver, dstCodePath);
+ }
+ }
+ if (ret != PackageManager.INSTALL_SUCCEEDED) {
+ if (!dstCodePath.exists()) {
+ return null;
+ }
+ mPm.removeCodePathLI(dstCodePath);
+ return null;
+ }
+
+ return dstCodePath;
+ }
+
+
+ @GuardedBy("mPm.mLock")
+ private void enableSystemPackageLPw(AndroidPackage pkg) {
+ mPm.mSettings.enableSystemPackageLPw(pkg.getPackageName());
+ }
+
+ /**
+ * Tries to delete system package.
+ */
+ @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
+ public void deleteSystemPackageLIF(DeletePackageAction action, PackageSetting deletedPs,
+ @NonNull int[] allUserHandles, int flags, @Nullable PackageRemovedInfo outInfo,
+ boolean writeSettings, int defParseFlags, List<ScanPartition> dirsToScanAsSystem)
+ throws SystemDeleteException {
+ final boolean applyUserRestrictions = outInfo != null && (outInfo.mOrigUsers != null);
+ final AndroidPackage deletedPkg = deletedPs.pkg;
+ // Confirm if the system package has been updated
+ // An updated system app can be deleted. This will also have to restore
+ // the system pkg from system partition
+ // reader
+ final PackageSetting disabledPs = action.mDisabledPs;
+ if (DEBUG_REMOVE) {
+ Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.getPackageName()
+ + " disabledPs=" + disabledPs);
+ }
+ Slog.d(TAG, "Deleting system pkg from data partition");
+
+ if (DEBUG_REMOVE) {
+ if (applyUserRestrictions) {
+ Slog.d(TAG, "Remembering install states:");
+ for (int userId : allUserHandles) {
+ final boolean finstalled = ArrayUtils.contains(outInfo.mOrigUsers, userId);
+ Slog.d(TAG, " u=" + userId + " inst=" + finstalled);
+ }
+ }
+ }
+
+ if (outInfo != null) {
+ // Delete the updated package
+ outInfo.mIsRemovedPackageSystemUpdate = true;
+ }
+
+ if (disabledPs.versionCode < deletedPs.versionCode) {
+ // Delete data for downgrades
+ flags &= ~PackageManager.DELETE_KEEP_DATA;
+ } else {
+ // Preserve data by setting flag
+ flags |= PackageManager.DELETE_KEEP_DATA;
+ }
+
+ mPm.deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles,
+ outInfo, writeSettings);
+
+ // writer
+ synchronized (mPm.mLock) {
+ // NOTE: The system package always needs to be enabled; even if it's for
+ // a compressed stub. If we don't, installing the system package fails
+ // during scan [scanning checks the disabled packages]. We will reverse
+ // this later, after we've "installed" the stub.
+ // Reinstate the old system package
+ enableSystemPackageLPw(disabledPs.pkg);
+ // Remove any native libraries from the upgraded package.
+ removeNativeBinariesLI(deletedPs);
+ }
+
+ // Install the system package
+ if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
+ try {
+ installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles,
+ outInfo == null ? null : outInfo.mOrigUsers, writeSettings, defParseFlags,
+ dirsToScanAsSystem);
+ } catch (PackageManagerException e) {
+ Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": "
+ + e.getMessage());
+ // TODO(b/194319951): can we avoid this; throw would come from scan...
+ throw new SystemDeleteException(e);
+ } finally {
+ if (disabledPs.pkg.isStub()) {
+ // We've re-installed the stub; make sure it's disabled here. If package was
+ // originally enabled, we'll install the compressed version of the application
+ // and re-enable it afterward.
+ final PackageSetting stubPs = mPm.mSettings.getPackageLPr(
+ deletedPkg.getPackageName());
+ if (stubPs != null) {
+ int userId = action.mUser == null
+ ? UserHandle.USER_ALL : action.mUser.getIdentifier();
+ if (userId == UserHandle.USER_ALL) {
+ for (int aUserId : allUserHandles) {
+ stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, aUserId, "android");
+ }
+ } else if (userId >= UserHandle.USER_SYSTEM) {
+ stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, userId, "android");
+ }
+ }
+ }
+ }
+ }
+
+ private void removeNativeBinariesLI(PackageSetting ps) {
+ if (ps != null) {
+ NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
+ }
+ }
+
+ /**
+ * Installs a package that's already on the system partition.
+ */
+ @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
+ private void installPackageFromSystemLIF(@NonNull String codePathString,
+ @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings,
+ int defParseFlags, List<ScanPartition> dirsToScanAsSystem)
+ throws PackageManagerException {
+ final File codePath = new File(codePathString);
+ @ParsingPackageUtils.ParseFlags int parseFlags =
+ defParseFlags
+ | ParsingPackageUtils.PARSE_MUST_BE_APK
+ | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
+ @PackageManagerService.ScanFlags int scanFlags = SCAN_AS_SYSTEM;
+ for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) {
+ ScanPartition partition = dirsToScanAsSystem.get(i);
+ if (partition.containsFile(codePath)) {
+ scanFlags |= partition.scanFlag;
+ if (partition.containsPrivApp(codePath)) {
+ scanFlags |= SCAN_AS_PRIVILEGED;
+ }
+ break;
+ }
+ }
+
+ final AndroidPackage pkg =
+ mPm.scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
+
+ PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
+
+ try {
+ // update shared libraries for the newly re-installed system package
+ mPm.updateSharedLibrariesLocked(pkg, pkgSetting, null, null,
+ Collections.unmodifiableMap(mPm.mPackages));
+ } catch (PackageManagerException e) {
+ Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
+ }
+
+ mPm.prepareAppDataAfterInstallLIF(pkg);
+
+ // writer
+ synchronized (mPm.mLock) {
+ PackageSetting ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
+
+ final boolean applyUserRestrictions = origUserHandles != null;
+ if (applyUserRestrictions) {
+ boolean installedStateChanged = false;
+ if (DEBUG_REMOVE) {
+ Slog.d(TAG, "Propagating install state across reinstall");
+ }
+ for (int userId : allUserHandles) {
+ final boolean installed = ArrayUtils.contains(origUserHandles, userId);
+ if (DEBUG_REMOVE) {
+ Slog.d(TAG, " user " + userId + " => " + installed);
+ }
+ if (installed != ps.getInstalled(userId)) {
+ installedStateChanged = true;
+ }
+ ps.setInstalled(installed, userId);
+ if (installed) {
+ ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId);
+ }
+ }
+ // Regardless of writeSettings we need to ensure that this restriction
+ // state propagation is persisted
+ mPm.mSettings.writeAllUsersPackageRestrictionsLPr();
+ if (installedStateChanged) {
+ mPm.mSettings.writeKernelMappingLPr(ps);
+ }
+ }
+
+ // The method below will take care of removing obsolete permissions and granting
+ // install permissions.
+ mPm.mPermissionManager.onPackageInstalled(pkg,
+ PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
+ UserHandle.USER_ALL);
+ for (final int userId : allUserHandles) {
+ if (applyUserRestrictions) {
+ mPm.mSettings.writePermissionStateForUserLPr(userId, false);
+ }
+ }
+
+ // can downgrade to reader here
+ if (writeSettings) {
+ mPm.writeSettingsLPrTEMP();
+ }
+ }
+ }
+
+ /**
+ * Adds a new package to the internal data structures during platform initialization.
+ * <p>After adding, the package is known to the system and available for querying.
+ * <p>For packages located on the device ROM [eg. packages located in /system, /vendor,
+ * etc...], additional checks are performed. Basic verification [such as ensuring
+ * matching signatures, checking version codes, etc...] occurs if the package is
+ * identical to a previously known package. If the package fails a signature check,
+ * the version installed on /data will be removed. If the version of the new package
+ * is less than or equal than the version on /data, it will be ignored.
+ * <p>Regardless of the package location, the results are applied to the internal
+ * structures and the package is made available to the rest of the system.
+ * <p>NOTE: The return value should be removed. It's the passed in package object.
+ */
+ @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
+ public AndroidPackage addForInitLI(ParsedPackage parsedPackage,
+ @ParsingPackageUtils.ParseFlags int parseFlags,
+ @PackageManagerService.ScanFlags int scanFlags, long currentTime,
+ @Nullable UserHandle user, AndroidPackage platformPackage, boolean isUpgrade,
+ boolean isPreNMR1Upgrade) throws PackageManagerException {
+ final boolean scanSystemPartition =
+ (parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
+ final String renamedPkgName;
+ final PackageSetting disabledPkgSetting;
+ final boolean isSystemPkgUpdated;
+ final boolean pkgAlreadyExists;
+ PackageSetting pkgSetting;
+
+ synchronized (mPm.mLock) {
+ renamedPkgName = mPm.mSettings.getRenamedPackageLPr(parsedPackage.getRealPackage());
+ final String realPkgName = PackageManagerService.getRealPackageName(parsedPackage,
+ renamedPkgName);
+ if (realPkgName != null) {
+ PackageManagerService.ensurePackageRenamed(parsedPackage, renamedPkgName);
+ }
+ final PackageSetting originalPkgSetting = mPm.getOriginalPackageLocked(parsedPackage,
+ renamedPkgName);
+ final PackageSetting installedPkgSetting = mPm.mSettings.getPackageLPr(
+ parsedPackage.getPackageName());
+ pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting;
+ pkgAlreadyExists = pkgSetting != null;
+ final String disabledPkgName = pkgAlreadyExists
+ ? pkgSetting.name : parsedPackage.getPackageName();
+ if (scanSystemPartition && !pkgAlreadyExists
+ && mPm.mSettings.getDisabledSystemPkgLPr(disabledPkgName) != null) {
+ // The updated-package data for /system apk remains inconsistently
+ // after the package data for /data apk is lost accidentally.
+ // To recover it, enable /system apk and install it as non-updated system app.
+ Slog.w(TAG, "Inconsistent package setting of updated system app for "
+ + disabledPkgName + ". To recover it, enable the system app"
+ + "and install it as non-updated system app.");
+ mPm.mSettings.removeDisabledSystemPackageLPw(disabledPkgName);
+ }
+ disabledPkgSetting = mPm.mSettings.getDisabledSystemPkgLPr(disabledPkgName);
+ isSystemPkgUpdated = disabledPkgSetting != null;
+
+ if (DEBUG_INSTALL && isSystemPkgUpdated) {
+ Slog.d(TAG, "updatedPkg = " + disabledPkgSetting);
+ }
+
+ final SharedUserSetting sharedUserSetting = (parsedPackage.getSharedUserId() != null)
+ ? mPm.mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(),
+ 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true)
+ : null;
+ if (DEBUG_PACKAGE_SCANNING
+ && (parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0
+ && sharedUserSetting != null) {
+ Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId()
+ + " (uid=" + sharedUserSetting.userId + "):"
+ + " packages=" + sharedUserSetting.packages);
+ }
+
+ if (scanSystemPartition) {
+ if (isSystemPkgUpdated) {
+ // we're updating the disabled package, so, scan it as the package setting
+ boolean isPlatformPackage = platformPackage != null
+ && Objects.equals(platformPackage.getPackageName(),
+ parsedPackage.getPackageName());
+ final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
+ null, disabledPkgSetting /* pkgSetting */,
+ null /* disabledPkgSetting */, null /* originalPkgSetting */,
+ null, parseFlags, scanFlags, isPlatformPackage, user, null);
+ PackageManagerService.applyPolicy(parsedPackage, scanFlags,
+ platformPackage, true);
+ final ScanResult scanResult =
+ mPm.scanPackageOnlyLI(request, mPm.mInjector,
+ mPm.mFactoryTest, -1L);
+ if (scanResult.mExistingSettingCopied
+ && scanResult.mRequest.mPkgSetting != null) {
+ scanResult.mRequest.mPkgSetting.updateFrom(scanResult.mPkgSetting);
+ }
+ }
+ }
+ }
+
+ final boolean newPkgChangedPaths = pkgAlreadyExists
+ && !pkgSetting.getPathString().equals(parsedPackage.getPath());
+ final boolean newPkgVersionGreater =
+ pkgAlreadyExists && parsedPackage.getLongVersionCode() > pkgSetting.versionCode;
+ final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
+ && newPkgChangedPaths && newPkgVersionGreater;
+ if (isSystemPkgBetter) {
+ // The version of the application on /system is greater than the version on
+ // /data. Switch back to the application on /system.
+ // It's safe to assume the application on /system will correctly scan. If not,
+ // there won't be a working copy of the application.
+ synchronized (mPm.mLock) {
+ // just remove the loaded entries from package lists
+ mPm.mPackages.remove(pkgSetting.name);
+ }
+
+ logCriticalInfo(Log.WARN,
+ "System package updated;"
+ + " name: " + pkgSetting.name
+ + "; " + pkgSetting.versionCode + " --> "
+ + parsedPackage.getLongVersionCode()
+ + "; " + pkgSetting.getPathString()
+ + " --> " + parsedPackage.getPath());
+
+ final InstallArgs args = mPm.createInstallArgsForExisting(
+ pkgSetting.getPathString(), getAppDexInstructionSets(
+ pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
+ args.cleanUpResourcesLI();
+ synchronized (mPm.mLock) {
+ mPm.mSettings.enableSystemPackageLPw(pkgSetting.name);
+ }
+ }
+
+ // The version of the application on the /system partition is less than or
+ // equal to the version on the /data partition. Throw an exception and use
+ // the application already installed on the /data partition.
+ if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) {
+ // In the case of a skipped package, commitReconciledScanResultLocked is not called to
+ // add the object to the "live" data structures, so this is the final mutation step
+ // for the package. Which means it needs to be finalized here to cache derived fields.
+ // This is relevant for cases where the disabled system package is used for flags or
+ // other metadata.
+ parsedPackage.hideAsFinal();
+ throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName()
+ + " at " + parsedPackage.getPath() + " ignored: updated version "
+ + (pkgAlreadyExists ? String.valueOf(pkgSetting.versionCode) : "unknown")
+ + " better than this " + parsedPackage.getLongVersionCode());
+ }
+
+ // Verify certificates against what was last scanned. Force re-collecting certificate in two
+ // special cases:
+ // 1) when scanning system, force re-collect only if system is upgrading.
+ // 2) when scannning /data, force re-collect only if the app is privileged (updated from
+ // preinstall, or treated as privileged, e.g. due to shared user ID).
+ final boolean forceCollect = scanSystemPartition ? isUpgrade
+ : PackageManagerServiceUtils.isApkVerificationForced(pkgSetting);
+ if (DEBUG_VERIFY && forceCollect) {
+ Slog.d(TAG, "Force collect certificate of " + parsedPackage.getPackageName());
+ }
+
+ // Full APK verification can be skipped during certificate collection, only if the file is
+ // in verified partition, or can be verified on access (when apk verity is enabled). In both
+ // cases, only data in Signing Block is verified instead of the whole file.
+ // TODO(b/136132412): skip for Incremental installation
+ final boolean skipVerify = scanSystemPartition
+ || (forceCollect && canSkipForcedPackageVerification(parsedPackage));
+ collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify,
+ isPreNMR1Upgrade);
+
+ // Reset profile if the application version is changed
+ maybeClearProfilesForUpgradesLI(pkgSetting, parsedPackage);
+
+ /*
+ * A new system app appeared, but we already had a non-system one of the
+ * same name installed earlier.
+ */
+ boolean shouldHideSystemApp = false;
+ // A new application appeared on /system, but, we already have a copy of
+ // the application installed on /data.
+ if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists
+ && !pkgSetting.isSystem()) {
+
+ if (!parsedPackage.getSigningDetails()
+ .checkCapability(pkgSetting.signatures.mSigningDetails,
+ SigningDetails.CertCapabilities.INSTALLED_DATA)
+ && !pkgSetting.signatures.mSigningDetails.checkCapability(
+ parsedPackage.getSigningDetails(),
+ SigningDetails.CertCapabilities.ROLLBACK)) {
+ logCriticalInfo(Log.WARN,
+ "System package signature mismatch;"
+ + " name: " + pkgSetting.name);
+ try (@SuppressWarnings("unused") PackageFreezer freezer = mPm.freezePackage(
+ parsedPackage.getPackageName(),
+ "scanPackageInternalLI")) {
+ mPm.deletePackageLIF(parsedPackage.getPackageName(), null, true,
+ mPm.mUserManager.getUserIds(), 0, null, false);
+ }
+ pkgSetting = null;
+ } else if (newPkgVersionGreater) {
+ // The application on /system is newer than the application on /data.
+ // Simply remove the application on /data [keeping application data]
+ // and replace it with the version on /system.
+ logCriticalInfo(Log.WARN,
+ "System package enabled;"
+ + " name: " + pkgSetting.name
+ + "; " + pkgSetting.versionCode + " --> "
+ + parsedPackage.getLongVersionCode()
+ + "; " + pkgSetting.getPathString() + " --> "
+ + parsedPackage.getPath());
+ InstallArgs args = mPm.createInstallArgsForExisting(
+ pkgSetting.getPathString(), getAppDexInstructionSets(
+ pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
+ synchronized (mPm.mInstallLock) {
+ args.cleanUpResourcesLI();
+ }
+ } else {
+ // The application on /system is older than the application on /data. Hide
+ // the application on /system and the version on /data will be scanned later
+ // and re-added like an update.
+ shouldHideSystemApp = true;
+ logCriticalInfo(Log.INFO,
+ "System package disabled;"
+ + " name: " + pkgSetting.name
+ + "; old: " + pkgSetting.getPathString() + " @ "
+ + pkgSetting.versionCode
+ + "; new: " + parsedPackage.getPath() + " @ "
+ + parsedPackage.getPath());
+ }
+ }
+
+ final ScanResult scanResult = mPm.scanPackageNewLI(parsedPackage, parseFlags, scanFlags
+ | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
+ if (scanResult.mSuccess) {
+ synchronized (mPm.mLock) {
+ boolean appIdCreated = false;
+ try {
+ final String pkgName = scanResult.mPkgSetting.name;
+ final Map<String, ReconciledPackage> reconcileResult =
+ mPm.reconcilePackagesLocked(
+ new ReconcileRequest(
+ Collections.singletonMap(pkgName, scanResult),
+ mPm.mSharedLibraries,
+ mPm.mPackages,
+ Collections.singletonMap(
+ pkgName,
+ mPm.getSettingsVersionForPackage(parsedPackage)),
+ Collections.singletonMap(pkgName,
+ mPm.getSharedLibLatestVersionSetting(scanResult))),
+ mPm.mSettings.getKeySetManagerService(), mPm.mInjector);
+ appIdCreated = mPm.optimisticallyRegisterAppId(scanResult);
+ mPm.commitReconciledScanResultLocked(
+ reconcileResult.get(pkgName), mPm.mUserManager.getUserIds());
+ } catch (PackageManagerException e) {
+ if (appIdCreated) {
+ mPm.cleanUpAppIdCreation(scanResult);
+ }
+ throw e;
+ }
+ }
+ }
+
+ if (shouldHideSystemApp) {
+ synchronized (mPm.mLock) {
+ mPm.mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true);
+ }
+ }
+ if (mPm.mIncrementalManager != null && isIncrementalPath(parsedPackage.getPath())) {
+ if (pkgSetting != null && pkgSetting.isPackageLoading()) {
+ // Continue monitoring loading progress of active incremental packages
+ final IncrementalStatesCallback incrementalStatesCallback =
+ new IncrementalStatesCallback(parsedPackage.getPackageName(), mPm);
+ pkgSetting.setIncrementalStatesCallback(incrementalStatesCallback);
+ mPm.mIncrementalManager.registerLoadingProgressCallback(parsedPackage.getPath(),
+ new IncrementalProgressListener(parsedPackage.getPackageName(), mPm));
+ }
+ }
+ return scanResult.mPkgSetting.pkg;
+ }
+
+ /**
+ * Returns if forced apk verification can be skipped for the whole package, including splits.
+ */
+ private boolean canSkipForcedPackageVerification(AndroidPackage pkg) {
+ if (!canSkipForcedApkVerification(pkg.getBaseApkPath())) {
+ return false;
+ }
+ // TODO: Allow base and splits to be verified individually.
+ String[] splitCodePaths = pkg.getSplitCodePaths();
+ if (!ArrayUtils.isEmpty(splitCodePaths)) {
+ for (int i = 0; i < splitCodePaths.length; i++) {
+ if (!canSkipForcedApkVerification(splitCodePaths[i])) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns if forced apk verification can be skipped, depending on current FSVerity setup and
+ * whether the apk contains signed root hash. Note that the signer's certificate still needs to
+ * match one in a trusted source, and should be done separately.
+ */
+ private boolean canSkipForcedApkVerification(String apkPath) {
+ if (!PackageManagerServiceUtils.isLegacyApkVerityEnabled()) {
+ return VerityUtils.hasFsverity(apkPath);
+ }
+
+ try {
+ final byte[] rootHashObserved = VerityUtils.generateApkVerityRootHash(apkPath);
+ if (rootHashObserved == null) {
+ return false; // APK does not contain Merkle tree root hash.
+ }
+ synchronized (mPm.mInstallLock) {
+ // Returns whether the observed root hash matches what kernel has.
+ mPm.mInstaller.assertFsverityRootHashMatches(apkPath, rootHashObserved);
+ return true;
+ }
+ } catch (Installer.InstallerException | IOException | DigestException
+ | NoSuchAlgorithmException e) {
+ Slog.w(TAG, "Error in fsverity check. Fallback to full apk verification.", e);
+ }
+ return false;
+ }
+
+ private void collectCertificatesLI(PackageSetting ps, ParsedPackage parsedPackage,
+ boolean forceCollect, boolean skipVerify, boolean mIsPreNMR1Upgrade)
+ throws PackageManagerException {
+ // When upgrading from pre-N MR1, verify the package time stamp using the package
+ // directory and not the APK file.
+ final long lastModifiedTime = mIsPreNMR1Upgrade
+ ? new File(parsedPackage.getPath()).lastModified()
+ : getLastModifiedTime(parsedPackage);
+ final Settings.VersionInfo settingsVersionForPackage =
+ mPm.getSettingsVersionForPackage(parsedPackage);
+ if (ps != null && !forceCollect
+ && ps.getPathString().equals(parsedPackage.getPath())
+ && ps.timeStamp == lastModifiedTime
+ && !PackageManagerService.isCompatSignatureUpdateNeeded(settingsVersionForPackage)
+ && !PackageManagerService.isRecoverSignatureUpdateNeeded(
+ settingsVersionForPackage)) {
+ if (ps.signatures.mSigningDetails.getSignatures() != null
+ && ps.signatures.mSigningDetails.getSignatures().length != 0
+ && ps.signatures.mSigningDetails.getSignatureSchemeVersion()
+ != SigningDetails.SignatureSchemeVersion.UNKNOWN) {
+ // Optimization: reuse the existing cached signing data
+ // if the package appears to be unchanged.
+ parsedPackage.setSigningDetails(
+ new SigningDetails(ps.signatures.mSigningDetails));
+ return;
+ }
+
+ Slog.w(TAG, "PackageSetting for " + ps.name
+ + " is missing signatures. Collecting certs again to recover them.");
+ } else {
+ Slog.i(TAG, parsedPackage.getPath() + " changed; collecting certs"
+ + (forceCollect ? " (forced)" : ""));
+ }
+
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
+ final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails(
+ input, parsedPackage, skipVerify);
+ if (result.isError()) {
+ throw new PackageManagerException(
+ result.getErrorCode(), result.getErrorMessage(), result.getException());
+ }
+ parsedPackage.setSigningDetails(result.getResult());
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ /**
+ * Clear the package profile if this was an upgrade and the package
+ * version was updated.
+ */
+ private void maybeClearProfilesForUpgradesLI(
+ @Nullable PackageSetting originalPkgSetting,
+ @NonNull AndroidPackage pkg) {
+ if (originalPkgSetting == null || !mPm.isDeviceUpgrading()) {
+ return;
+ }
+ if (originalPkgSetting.versionCode == pkg.getVersionCode()) {
+ return;
+ }
+
+ mPm.clearAppProfilesLIF(pkg);
+ if (DEBUG_INSTALL) {
+ Slog.d(TAG, originalPkgSetting.name
+ + " clear profile due to version change "
+ + originalPkgSetting.versionCode + " != "
+ + pkg.getVersionCode());
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/InstallParams.java b/services/core/java/com/android/server/pm/InstallParams.java
index 45ce3980d543..934775a9a1b5 100644
--- a/services/core/java/com/android/server/pm/InstallParams.java
+++ b/services/core/java/com/android/server/pm/InstallParams.java
@@ -163,14 +163,12 @@ final class InstallParams extends HandlerParams {
final int mDataLoaderType;
final long mRequiredInstalledVersionCode;
final PackageLite mPackageLite;
- @NonNull final PackageManagerService mPm;
InstallParams(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer,
int installFlags, InstallSource installSource, String volumeUuid,
UserHandle user, String packageAbiOverride, PackageLite packageLite,
PackageManagerService pm) {
- super(user);
- mPm = pm;
+ super(user, pm);
mOriginInfo = originInfo;
mMoveInfo = moveInfo;
mObserver = observer;
@@ -195,8 +193,7 @@ final class InstallParams extends HandlerParams {
PackageInstaller.SessionParams sessionParams, InstallSource installSource,
UserHandle user, SigningDetails signingDetails, int installerUid,
PackageLite packageLite, PackageManagerService pm) {
- super(user);
- mPm = pm;
+ super(user, pm);
mOriginInfo = OriginInfo.fromStagedFile(stagedDir);
mMoveInfo = null;
mInstallReason = fixUpInstallReason(
@@ -373,7 +370,7 @@ final class InstallParams extends HandlerParams {
// state can change within this delay and hence we need to re-verify certain conditions.
boolean isStaged = (mInstallFlags & INSTALL_STAGED) != 0;
if (isStaged) {
- Pair<Integer, String> ret = mPm.verifyReplacingVersionCode(
+ Pair<Integer, String> ret = verifyReplacingVersionCode(
pkgLite, mRequiredInstalledVersionCode, mInstallFlags);
mRet = ret.first;
if (mRet != INSTALL_SUCCEEDED) {
@@ -622,7 +619,7 @@ final class InstallParams extends HandlerParams {
Map<String, ReconciledPackage> reconciledPackages;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
- reconciledPackages = PackageManagerService.reconcilePackagesLocked(
+ reconciledPackages = mPm.reconcilePackagesLocked(
reconcileRequest, mPm.mSettings.getKeySetManagerService(),
mPm.mInjector);
} catch (ReconcileFailure e) {
@@ -2075,7 +2072,7 @@ final class InstallParams extends HandlerParams {
throws PackageManagerException {
final Message msg = mPm.mHandler.obtainMessage(INIT_COPY);
final MultiPackageInstallParams params =
- new MultiPackageInstallParams(this, children);
+ new MultiPackageInstallParams(this, children, mPm);
params.setTraceMethod("installStageMultiPackage")
.setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -2107,9 +2104,10 @@ final class InstallParams extends HandlerParams {
private final List<InstallParams> mChildParams;
private final Map<InstallArgs, Integer> mCurrentState;
- MultiPackageInstallParams(InstallParams parent, List<InstallParams> childParams)
+ MultiPackageInstallParams(InstallParams parent, List<InstallParams> childParams,
+ PackageManagerService pm)
throws PackageManagerException {
- super(parent.getUser());
+ super(parent.getUser(), pm);
if (childParams.size() == 0) {
throw new PackageManagerException("No child sessions found!");
}
@@ -2159,4 +2157,6 @@ final class InstallParams extends HandlerParams {
installRequests);
}
}
+
+
}
diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java
new file mode 100644
index 000000000000..44a973eac05c
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageHandler.java
@@ -0,0 +1,783 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
+import static android.os.PowerExemptionManager.REASON_PACKAGE_REPLACED;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import static com.android.server.pm.PackageManagerService.CHECK_PENDING_INTEGRITY_VERIFICATION;
+import static com.android.server.pm.PackageManagerService.CHECK_PENDING_VERIFICATION;
+import static com.android.server.pm.PackageManagerService.DEBUG_BACKUP;
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
+import static com.android.server.pm.PackageManagerService.DEFAULT_VERIFICATION_RESPONSE;
+import static com.android.server.pm.PackageManagerService.DEFERRED_NO_KILL_INSTALL_OBSERVER;
+import static com.android.server.pm.PackageManagerService.DEFERRED_NO_KILL_POST_DELETE;
+import static com.android.server.pm.PackageManagerService.DOMAIN_VERIFICATION;
+import static com.android.server.pm.PackageManagerService.EMPTY_INT_ARRAY;
+import static com.android.server.pm.PackageManagerService.ENABLE_ROLLBACK_STATUS;
+import static com.android.server.pm.PackageManagerService.ENABLE_ROLLBACK_TIMEOUT;
+import static com.android.server.pm.PackageManagerService.INIT_COPY;
+import static com.android.server.pm.PackageManagerService.INSTANT_APP_RESOLUTION_PHASE_TWO;
+import static com.android.server.pm.PackageManagerService.INTEGRITY_VERIFICATION_COMPLETE;
+import static com.android.server.pm.PackageManagerService.PACKAGE_VERIFIED;
+import static com.android.server.pm.PackageManagerService.POST_INSTALL;
+import static com.android.server.pm.PackageManagerService.SEND_PENDING_BROADCAST;
+import static com.android.server.pm.PackageManagerService.SNAPSHOT_UNCORK;
+import static com.android.server.pm.PackageManagerService.TAG;
+import static com.android.server.pm.PackageManagerService.TRACE_SNAPSHOTS;
+import static com.android.server.pm.PackageManagerService.WRITE_PACKAGE_LIST;
+import static com.android.server.pm.PackageManagerService.WRITE_PACKAGE_RESTRICTIONS;
+import static com.android.server.pm.PackageManagerService.WRITE_SETTINGS;
+
+import android.content.Intent;
+import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.InstantAppRequest;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.stats.storage.StorageEnums;
+import android.util.ArrayMap;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.EventLogTags;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
+import dalvik.system.VMRuntime;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Part of PackageManagerService that handles events.
+ */
+public class PackageHandler extends Handler {
+ final PackageManagerService mPm;
+ PackageHandler(Looper looper, PackageManagerService pm) {
+ super(looper);
+ mPm = pm;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ doHandleMessage(msg);
+ } finally {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ }
+ }
+
+ void doHandleMessage(Message msg) {
+ switch (msg.what) {
+ case INIT_COPY: {
+ HandlerParams params = (HandlerParams) msg.obj;
+ if (params != null) {
+ if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
+ Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+ System.identityHashCode(params));
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
+ params.startCopy();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ break;
+ }
+ case SEND_PENDING_BROADCAST: {
+ String[] packages;
+ ArrayList<String>[] components;
+ int size = 0;
+ int[] uids;
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ synchronized (mPm.mLock) {
+ size = mPm.mPendingBroadcasts.size();
+ if (size <= 0) {
+ // Nothing to be done. Just return
+ return;
+ }
+ packages = new String[size];
+ components = new ArrayList[size];
+ uids = new int[size];
+ int i = 0; // filling out the above arrays
+
+ for (int n = 0; n < mPm.mPendingBroadcasts.userIdCount(); n++) {
+ final int packageUserId = mPm.mPendingBroadcasts.userIdAt(n);
+ final ArrayMap<String, ArrayList<String>> componentsToBroadcast =
+ mPm.mPendingBroadcasts.packagesForUserId(packageUserId);
+ final int numComponents = componentsToBroadcast.size();
+ for (int index = 0; i < size && index < numComponents; index++) {
+ packages[i] = componentsToBroadcast.keyAt(index);
+ components[i] = componentsToBroadcast.valueAt(index);
+ final PackageSetting ps = mPm.mSettings.getPackageLPr(packages[i]);
+ uids[i] = (ps != null)
+ ? UserHandle.getUid(packageUserId, ps.appId)
+ : -1;
+ i++;
+ }
+ }
+ size = i;
+ mPm.mPendingBroadcasts.clear();
+ }
+ // Send broadcasts
+ for (int i = 0; i < size; i++) {
+ mPm.sendPackageChangedBroadcast(packages[i], true /* dontKillApp */,
+ components[i], uids[i], null /* reason */);
+ }
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ break;
+ }
+ case POST_INSTALL: {
+ if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
+
+ PackageManagerService.PostInstallData data = mPm.mRunningInstalls.get(msg.arg1);
+ final boolean didRestore = (msg.arg2 != 0);
+ mPm.mRunningInstalls.delete(msg.arg1);
+
+ if (data != null && data.res.mFreezer != null) {
+ data.res.mFreezer.close();
+ }
+
+ if (data != null && data.mPostInstallRunnable != null) {
+ data.mPostInstallRunnable.run();
+ } else if (data != null && data.args != null) {
+ InstallArgs args = data.args;
+ PackageInstalledInfo parentRes = data.res;
+
+ final boolean killApp = (args.mInstallFlags
+ & PackageManager.INSTALL_DONT_KILL_APP) == 0;
+ final boolean virtualPreload = ((args.mInstallFlags
+ & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
+
+ handlePackagePostInstall(parentRes, killApp, virtualPreload,
+ didRestore, args.mInstallSource.installerPackageName,
+ args.mObserver, args.mDataLoaderType);
+
+ // Log tracing if needed
+ if (args.mTraceMethod != null) {
+ Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.mTraceMethod,
+ args.mTraceCookie);
+ }
+ } else if (DEBUG_INSTALL) {
+ // No post-install when we run restore from installExistingPackageForUser
+ Slog.i(TAG, "Nothing to do for post-install token " + msg.arg1);
+ }
+
+ Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
+ } break;
+ case DEFERRED_NO_KILL_POST_DELETE: {
+ synchronized (mPm.mInstallLock) {
+ InstallArgs args = (InstallArgs) msg.obj;
+ if (args != null) {
+ args.doPostDeleteLI(true);
+ }
+ }
+ } break;
+ case DEFERRED_NO_KILL_INSTALL_OBSERVER: {
+ String packageName = (String) msg.obj;
+ if (packageName != null) {
+ mPm.notifyInstallObserver(packageName);
+ }
+ } break;
+ case WRITE_SETTINGS: {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ synchronized (mPm.mLock) {
+ removeMessages(WRITE_SETTINGS);
+ removeMessages(WRITE_PACKAGE_RESTRICTIONS);
+ mPm.writeSettingsLPrTEMP();
+ mPm.mDirtyUsers.clear();
+ }
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ } break;
+ case WRITE_PACKAGE_RESTRICTIONS: {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ synchronized (mPm.mLock) {
+ removeMessages(WRITE_PACKAGE_RESTRICTIONS);
+ for (int userId : mPm.mDirtyUsers) {
+ mPm.mSettings.writePackageRestrictionsLPr(userId);
+ }
+ mPm.mDirtyUsers.clear();
+ }
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ } break;
+ case WRITE_PACKAGE_LIST: {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ synchronized (mPm.mLock) {
+ removeMessages(WRITE_PACKAGE_LIST);
+ mPm.mSettings.writePackageListLPr(msg.arg1);
+ }
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ } break;
+ case CHECK_PENDING_VERIFICATION: {
+ final int verificationId = msg.arg1;
+ final PackageVerificationState state = mPm.mPendingVerification.get(verificationId);
+
+ if ((state != null) && !state.isVerificationComplete()
+ && !state.timeoutExtended()) {
+ final VerificationParams params = state.getVerificationParams();
+ final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
+
+ String errorMsg = "Verification timed out for " + originUri;
+ Slog.i(TAG, errorMsg);
+
+ final UserHandle user = params.getUser();
+ if (getDefaultVerificationResponse(user)
+ == PackageManager.VERIFICATION_ALLOW) {
+ Slog.i(TAG, "Continuing with installation of " + originUri);
+ state.setVerifierResponse(Binder.getCallingUid(),
+ PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
+ mPm.broadcastPackageVerified(verificationId, originUri,
+ PackageManager.VERIFICATION_ALLOW, null, params.mDataLoaderType,
+ user);
+ } else {
+ mPm.broadcastPackageVerified(verificationId, originUri,
+ PackageManager.VERIFICATION_REJECT, null,
+ params.mDataLoaderType, user);
+ params.setReturnCode(
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg);
+ state.setVerifierResponse(Binder.getCallingUid(),
+ PackageManager.VERIFICATION_REJECT);
+ }
+
+ if (state.areAllVerificationsComplete()) {
+ mPm.mPendingVerification.remove(verificationId);
+ }
+
+ Trace.asyncTraceEnd(
+ TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
+
+ params.handleVerificationFinished();
+
+ }
+ break;
+ }
+ case CHECK_PENDING_INTEGRITY_VERIFICATION: {
+ final int verificationId = msg.arg1;
+ final PackageVerificationState state = mPm.mPendingVerification.get(verificationId);
+
+ if (state != null && !state.isIntegrityVerificationComplete()) {
+ final VerificationParams params = state.getVerificationParams();
+ final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
+
+ String errorMsg = "Integrity verification timed out for " + originUri;
+ Slog.i(TAG, errorMsg);
+
+ state.setIntegrityVerificationResult(
+ getDefaultIntegrityVerificationResponse());
+
+ if (getDefaultIntegrityVerificationResponse()
+ == PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) {
+ Slog.i(TAG, "Integrity check times out, continuing with " + originUri);
+ } else {
+ params.setReturnCode(
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+ errorMsg);
+ }
+
+ if (state.areAllVerificationsComplete()) {
+ mPm.mPendingVerification.remove(verificationId);
+ }
+
+ Trace.asyncTraceEnd(
+ TRACE_TAG_PACKAGE_MANAGER,
+ "integrity_verification",
+ verificationId);
+
+ params.handleIntegrityVerificationFinished();
+ }
+ break;
+ }
+ case PACKAGE_VERIFIED: {
+ final int verificationId = msg.arg1;
+
+ final PackageVerificationState state = mPm.mPendingVerification.get(verificationId);
+ if (state == null) {
+ Slog.w(TAG, "Verification with id " + verificationId
+ + " not found."
+ + " It may be invalid or overridden by integrity verification");
+ break;
+ }
+
+ final PackageVerificationResponse response = (PackageVerificationResponse) msg.obj;
+
+ state.setVerifierResponse(response.callerUid, response.code);
+
+ if (state.isVerificationComplete()) {
+ final VerificationParams params = state.getVerificationParams();
+ final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
+
+ if (state.isInstallAllowed()) {
+ mPm.broadcastPackageVerified(verificationId, originUri,
+ response.code, null, params.mDataLoaderType, params.getUser());
+ } else {
+ params.setReturnCode(
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+ "Install not allowed");
+ }
+
+ if (state.areAllVerificationsComplete()) {
+ mPm.mPendingVerification.remove(verificationId);
+ }
+
+ Trace.asyncTraceEnd(
+ TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
+
+ params.handleVerificationFinished();
+ }
+
+ break;
+ }
+ case INTEGRITY_VERIFICATION_COMPLETE: {
+ final int verificationId = msg.arg1;
+
+ final PackageVerificationState state = mPm.mPendingVerification.get(verificationId);
+ if (state == null) {
+ Slog.w(TAG, "Integrity verification with id " + verificationId
+ + " not found. It may be invalid or overridden by verifier");
+ break;
+ }
+
+ final int response = (Integer) msg.obj;
+ final VerificationParams params = state.getVerificationParams();
+ final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
+
+ state.setIntegrityVerificationResult(response);
+
+ if (response == PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) {
+ Slog.i(TAG, "Integrity check passed for " + originUri);
+ } else {
+ params.setReturnCode(
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+ "Integrity check failed for " + originUri);
+ }
+
+ if (state.areAllVerificationsComplete()) {
+ mPm.mPendingVerification.remove(verificationId);
+ }
+
+ Trace.asyncTraceEnd(
+ TRACE_TAG_PACKAGE_MANAGER,
+ "integrity_verification",
+ verificationId);
+
+ params.handleIntegrityVerificationFinished();
+ break;
+ }
+ case INSTANT_APP_RESOLUTION_PHASE_TWO: {
+ InstantAppResolver.doInstantAppResolutionPhaseTwo(mPm.mContext,
+ mPm.mInstantAppResolverConnection,
+ (InstantAppRequest) msg.obj,
+ mPm.mInstantAppInstallerActivity,
+ mPm.mHandler);
+ break;
+ }
+ case ENABLE_ROLLBACK_STATUS: {
+ final int enableRollbackToken = msg.arg1;
+ final int enableRollbackCode = msg.arg2;
+ final VerificationParams params =
+ mPm.mPendingEnableRollback.get(enableRollbackToken);
+ if (params == null) {
+ Slog.w(TAG, "Invalid rollback enabled token "
+ + enableRollbackToken + " received");
+ break;
+ }
+
+ mPm.mPendingEnableRollback.remove(enableRollbackToken);
+
+ if (enableRollbackCode != PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED) {
+ final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
+ Slog.w(TAG, "Failed to enable rollback for " + originUri);
+ Slog.w(TAG, "Continuing with installation of " + originUri);
+ }
+
+ Trace.asyncTraceEnd(
+ TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
+
+ params.handleRollbackEnabled();
+ break;
+ }
+ case ENABLE_ROLLBACK_TIMEOUT: {
+ final int enableRollbackToken = msg.arg1;
+ final int sessionId = msg.arg2;
+ final VerificationParams params =
+ mPm.mPendingEnableRollback.get(enableRollbackToken);
+ if (params != null) {
+ final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
+
+ Slog.w(TAG, "Enable rollback timed out for " + originUri);
+ mPm.mPendingEnableRollback.remove(enableRollbackToken);
+
+ Slog.w(TAG, "Continuing with installation of " + originUri);
+ Trace.asyncTraceEnd(
+ TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
+ params.handleRollbackEnabled();
+ Intent rollbackTimeoutIntent = new Intent(
+ Intent.ACTION_CANCEL_ENABLE_ROLLBACK);
+ rollbackTimeoutIntent.putExtra(
+ PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
+ sessionId);
+ rollbackTimeoutIntent.addFlags(
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mPm.mContext.sendBroadcastAsUser(rollbackTimeoutIntent, UserHandle.SYSTEM,
+ android.Manifest.permission.PACKAGE_ROLLBACK_AGENT);
+ }
+ break;
+ }
+ case DOMAIN_VERIFICATION: {
+ int messageCode = msg.arg1;
+ Object object = msg.obj;
+ mPm.mDomainVerificationManager.runMessage(messageCode, object);
+ break;
+ }
+ case SNAPSHOT_UNCORK: {
+ int corking = mPm.sSnapshotCorked.decrementAndGet();
+ if (TRACE_SNAPSHOTS && corking == 0) {
+ Log.e(TAG, "snapshot: corking goes to zero in message handler");
+ }
+ break;
+ }
+ }
+ }
+
+ private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp,
+ boolean virtualPreload, boolean launchedForRestore, String installerPackage,
+ IPackageInstallObserver2 installObserver, int dataLoaderType) {
+ boolean succeeded = res.mReturnCode == PackageManager.INSTALL_SUCCEEDED;
+ final boolean update = res.mRemovedInfo != null && res.mRemovedInfo.mRemovedPackage != null;
+ final String packageName = res.mName;
+ final PackageSetting pkgSetting = succeeded ? mPm.getPackageSetting(packageName) : null;
+ final boolean removedBeforeUpdate = (pkgSetting == null)
+ || (pkgSetting.isSystem() && !pkgSetting.getPathString().equals(
+ res.mPkg.getPath()));
+ if (succeeded && removedBeforeUpdate) {
+ Slog.e(TAG, packageName + " was removed before handlePackagePostInstall "
+ + "could be executed");
+ res.mReturnCode = INSTALL_FAILED_PACKAGE_CHANGED;
+ res.mReturnMsg = "Package was removed before install could complete.";
+
+ // Remove the update failed package's older resources safely now
+ InstallArgs args = res.mRemovedInfo != null ? res.mRemovedInfo.mArgs : null;
+ if (args != null) {
+ synchronized (mPm.mInstallLock) {
+ args.doPostDeleteLI(true);
+ }
+ }
+ mPm.notifyInstallObserver(res, installObserver);
+ return;
+ }
+
+ if (succeeded) {
+ // Clear the uid cache after we installed a new package.
+ mPm.mPerUidReadTimeoutsCache = null;
+
+ // Send the removed broadcasts
+ if (res.mRemovedInfo != null) {
+ res.mRemovedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
+ }
+
+ final String installerPackageName =
+ res.mInstallerPackageName != null
+ ? res.mInstallerPackageName
+ : res.mRemovedInfo != null
+ ? res.mRemovedInfo.mInstallerPackageName
+ : null;
+
+ synchronized (mPm.mLock) {
+ mPm.mInstantAppRegistry.onPackageInstalledLPw(res.mPkg, res.mNewUsers);
+ }
+
+ // Determine the set of users who are adding this package for
+ // the first time vs. those who are seeing an update.
+ int[] firstUserIds = EMPTY_INT_ARRAY;
+ int[] firstInstantUserIds = EMPTY_INT_ARRAY;
+ int[] updateUserIds = EMPTY_INT_ARRAY;
+ int[] instantUserIds = EMPTY_INT_ARRAY;
+ final boolean allNewUsers = res.mOrigUsers == null || res.mOrigUsers.length == 0;
+ for (int newUser : res.mNewUsers) {
+ final boolean isInstantApp = pkgSetting.getInstantApp(newUser);
+ if (allNewUsers) {
+ if (isInstantApp) {
+ firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
+ } else {
+ firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
+ }
+ continue;
+ }
+ boolean isNew = true;
+ for (int origUser : res.mOrigUsers) {
+ if (origUser == newUser) {
+ isNew = false;
+ break;
+ }
+ }
+ if (isNew) {
+ if (isInstantApp) {
+ firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
+ } else {
+ firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
+ }
+ } else {
+ if (isInstantApp) {
+ instantUserIds = ArrayUtils.appendInt(instantUserIds, newUser);
+ } else {
+ updateUserIds = ArrayUtils.appendInt(updateUserIds, newUser);
+ }
+ }
+ }
+
+ // Send installed broadcasts if the package is not a static shared lib.
+ if (res.mPkg.getStaticSharedLibName() == null) {
+ mPm.mProcessLoggingHandler.invalidateBaseApkHash(res.mPkg.getBaseApkPath());
+
+ // Send added for users that see the package for the first time
+ // sendPackageAddedForNewUsers also deals with system apps
+ int appId = UserHandle.getAppId(res.mUid);
+ boolean isSystem = res.mPkg.isSystem();
+ mPm.sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
+ virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds,
+ dataLoaderType);
+
+ // Send added for users that don't see the package for the first time
+ Bundle extras = new Bundle(1);
+ extras.putInt(Intent.EXTRA_UID, res.mUid);
+ if (update) {
+ extras.putBoolean(Intent.EXTRA_REPLACING, true);
+ }
+ extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
+ // Send to all running apps.
+ final SparseArray<int[]> newBroadcastAllowList;
+
+ synchronized (mPm.mLock) {
+ newBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(
+ mPm.getPackageSettingInternal(res.mName, Process.SYSTEM_UID),
+ updateUserIds, mPm.mSettings.getPackagesLocked());
+ }
+ mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+ extras, 0 /*flags*/,
+ null /*targetPackage*/, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds, newBroadcastAllowList, null);
+ if (installerPackageName != null) {
+ // Send to the installer, even if it's not running.
+ mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+ extras, 0 /*flags*/,
+ installerPackageName, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
+ }
+ // if the required verifier is defined, but, is not the installer of record
+ // for the package, it gets notified
+ final boolean notifyVerifier = mPm.mRequiredVerifierPackage != null
+ && !mPm.mRequiredVerifierPackage.equals(installerPackageName);
+ if (notifyVerifier) {
+ mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+ extras, 0 /*flags*/,
+ mPm.mRequiredVerifierPackage, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
+ }
+ // If package installer is defined, notify package installer about new
+ // app installed
+ if (mPm.mRequiredInstallerPackage != null) {
+ mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+ extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND /*flags*/,
+ mPm.mRequiredInstallerPackage, null /*finishedReceiver*/,
+ firstUserIds, instantUserIds, null /* broadcastAllowList */, null);
+ }
+
+ // Send replaced for users that don't see the package for the first time
+ if (update) {
+ mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
+ packageName, extras, 0 /*flags*/,
+ null /*targetPackage*/, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds, res.mRemovedInfo.mBroadcastAllowList,
+ null);
+ if (installerPackageName != null) {
+ mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
+ extras, 0 /*flags*/,
+ installerPackageName, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds, null /*broadcastAllowList*/, null);
+ }
+ if (notifyVerifier) {
+ mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
+ extras, 0 /*flags*/,
+ mPm.mRequiredVerifierPackage, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds, null /*broadcastAllowList*/, null);
+ }
+ mPm.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
+ null /*package*/, null /*extras*/, 0 /*flags*/,
+ packageName /*targetPackage*/,
+ null /*finishedReceiver*/, updateUserIds, instantUserIds,
+ null /*broadcastAllowList*/,
+ mPm.getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED)
+ .toBundle());
+ } else if (launchedForRestore && !res.mPkg.isSystem()) {
+ // First-install and we did a restore, so we're responsible for the
+ // first-launch broadcast.
+ if (DEBUG_BACKUP) {
+ Slog.i(TAG, "Post-restore of " + packageName
+ + " sending FIRST_LAUNCH in " + Arrays.toString(firstUserIds));
+ }
+ mPm.sendFirstLaunchBroadcast(packageName, installerPackage,
+ firstUserIds, firstInstantUserIds);
+ }
+
+ // Send broadcast package appeared if external for all users
+ if (res.mPkg.isExternalStorage()) {
+ if (!update) {
+ final StorageManager storage = mPm.mInjector.getSystemService(
+ StorageManager.class);
+ VolumeInfo volume =
+ storage.findVolumeByUuid(
+ res.mPkg.getStorageUuid().toString());
+ int packageExternalStorageType =
+ PackageManagerService.getPackageExternalStorageType(volume,
+ res.mPkg.isExternalStorage());
+ // If the package was installed externally, log it.
+ if (packageExternalStorageType != StorageEnums.UNKNOWN) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
+ packageExternalStorageType, packageName);
+ }
+ }
+ if (DEBUG_INSTALL) {
+ Slog.i(TAG, "upgrading pkg " + res.mPkg + " is external");
+ }
+ final int[] uidArray = new int[]{res.mPkg.getUid()};
+ ArrayList<String> pkgList = new ArrayList<>(1);
+ pkgList.add(packageName);
+ mPm.sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
+ }
+ } else if (!ArrayUtils.isEmpty(res.mLibraryConsumers)) { // if static shared lib
+ for (int i = 0; i < res.mLibraryConsumers.size(); i++) {
+ AndroidPackage pkg = res.mLibraryConsumers.get(i);
+ // send broadcast that all consumers of the static shared library have changed
+ mPm.sendPackageChangedBroadcast(pkg.getPackageName(), false /* dontKillApp */,
+ new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
+ pkg.getUid(), null);
+ }
+ }
+
+ // Work that needs to happen on first install within each user
+ if (firstUserIds != null && firstUserIds.length > 0) {
+ for (int userId : firstUserIds) {
+ mPm.restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
+ userId);
+ }
+ }
+
+ if (allNewUsers && !update) {
+ mPm.notifyPackageAdded(packageName, res.mUid);
+ } else {
+ mPm.notifyPackageChanged(packageName, res.mUid);
+ }
+
+ // Log current value of "unknown sources" setting
+ EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
+ getUnknownSourcesSettings());
+
+ // Remove the replaced package's older resources safely now
+ InstallArgs args = res.mRemovedInfo != null ? res.mRemovedInfo.mArgs : null;
+ if (args != null) {
+ if (!killApp) {
+ // If we didn't kill the app, defer the deletion of code/resource files, since
+ // they may still be in use by the running application. This mitigates problems
+ // in cases where resources or code is loaded by a new Activity before
+ // ApplicationInfo changes have propagated to all application threads.
+ mPm.scheduleDeferredNoKillPostDelete(args);
+ } else {
+ synchronized (mPm.mInstallLock) {
+ args.doPostDeleteLI(true);
+ }
+ }
+ } else {
+ // Force a gc to clear up things. Ask for a background one, it's fine to go on
+ // and not block here.
+ VMRuntime.getRuntime().requestConcurrentGC();
+ }
+
+ // Notify DexManager that the package was installed for new users.
+ // The updated users should already be indexed and the package code paths
+ // should not change.
+ // Don't notify the manager for ephemeral apps as they are not expected to
+ // survive long enough to benefit of background optimizations.
+ for (int userId : firstUserIds) {
+ PackageInfo info = mPm.getPackageInfo(packageName, /*flags*/ 0, userId);
+ // There's a race currently where some install events may interleave with an
+ // uninstall. This can lead to package info being null (b/36642664).
+ if (info != null) {
+ mPm.getDexManager().notifyPackageInstalled(info, userId);
+ }
+ }
+ }
+
+ final boolean deferInstallObserver = succeeded && update && !killApp;
+ if (deferInstallObserver) {
+ mPm.scheduleDeferredNoKillInstallObserver(res, installObserver);
+ } else {
+ mPm.notifyInstallObserver(res, installObserver);
+ }
+ }
+
+ /**
+ * Get the default verification agent response code.
+ *
+ * @return default verification response code
+ */
+ private int getDefaultVerificationResponse(UserHandle user) {
+ if (mPm.mUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS,
+ user.getIdentifier())) {
+ return PackageManager.VERIFICATION_REJECT;
+ }
+ return android.provider.Settings.Global.getInt(mPm.mContext.getContentResolver(),
+ android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
+ DEFAULT_VERIFICATION_RESPONSE);
+ }
+
+ /**
+ * Get the default integrity verification response code.
+ */
+ private int getDefaultIntegrityVerificationResponse() {
+ // We are not exposing this as a user-configurable setting because we don't want to provide
+ // an easy way to get around the integrity check.
+ return PackageManager.VERIFICATION_REJECT;
+ }
+
+ /**
+ * Get the "allow unknown sources" setting.
+ *
+ * @return the current "allow unknown sources" setting
+ */
+ private int getUnknownSourcesSettings() {
+ return android.provider.Settings.Secure.getIntForUser(mPm.mContext.getContentResolver(),
+ android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS,
+ -1, UserHandle.USER_SYSTEM);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3cd41d30aa86..2c2884f4e76f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -39,11 +39,9 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LI
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
import static android.content.pm.PackageManager.INSTALL_FAILED_PROCESS_NOT_DEFINED;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
-import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
import static android.content.pm.PackageManager.INSTALL_INTERNAL;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
-import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
@@ -74,7 +72,6 @@ import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE;
import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
-import static android.os.PowerWhitelistManager.REASON_PACKAGE_REPLACED;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.incremental.IncrementalManager.isIncrementalPath;
@@ -86,10 +83,7 @@ import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
import static com.android.internal.annotations.VisibleForTesting.Visibility;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
-import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
-import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME;
-import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
@@ -98,13 +92,10 @@ import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefa
import static com.android.server.pm.PackageManagerServiceUtils.comparePackageSignatures;
import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
-import static com.android.server.pm.PackageManagerServiceUtils.decompressFile;
import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride;
import static com.android.server.pm.PackageManagerServiceUtils.dumpCriticalInfo;
-import static com.android.server.pm.PackageManagerServiceUtils.getCompressedFiles;
import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
-import static com.android.server.pm.PackageManagerServiceUtils.makeDirRecursive;
import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
import static com.android.server.pm.parsing.PackageInfoUtils.checkUseInstalledOrHidden;
@@ -175,7 +166,6 @@ import android.content.pm.KeySet;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageChangeEvent;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ComponentEnabledSetting;
@@ -188,7 +178,6 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PackageManagerInternal.PrivateResolveFlags;
import android.content.pm.PackagePartitions;
-import android.content.pm.PackagePartitions.SystemPartition;
import android.content.pm.PackageStats;
import android.content.pm.PackageUserState;
import android.content.pm.ParceledListSlice;
@@ -202,7 +191,6 @@ import android.content.pm.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
-import android.content.pm.SigningDetails.SignatureSchemeVersion;
import android.content.pm.SigningInfo;
import android.content.pm.StagedApexInfo;
import android.content.pm.SuspendDialogInfo;
@@ -275,7 +263,6 @@ import android.provider.Settings.Secure;
import android.security.KeyStore;
import android.service.pm.PackageServiceDumpProto;
import android.stats.storage.StorageEnums;
-import android.system.ErrnoException;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
@@ -311,13 +298,11 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.F2fsUtils;
-import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
import com.android.internal.content.om.OverlayConfig;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.SomeArgs;
import com.android.internal.policy.AttributeCache;
-import com.android.internal.security.VerityUtils;
import com.android.internal.telephony.CarrierAppUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
@@ -387,7 +372,6 @@ import com.android.server.wm.ActivityTaskManagerInternal;
import dalvik.system.VMRuntime;
-import libcore.io.IoUtils;
import libcore.util.EmptyArray;
import libcore.util.HexEncoding;
@@ -408,7 +392,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.nio.charset.StandardCharsets;
-import java.security.DigestException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
@@ -489,7 +472,7 @@ public class PackageManagerService extends IPackageManager.Stub
static final boolean DEBUG_PREFERRED = false;
static final boolean DEBUG_UPGRADE = false;
static final boolean DEBUG_DOMAIN_VERIFICATION = false;
- private static final boolean DEBUG_BACKUP = false;
+ static final boolean DEBUG_BACKUP = false;
public static final boolean DEBUG_INSTALL = false;
public static final boolean DEBUG_REMOVE = false;
private static final boolean DEBUG_BROADCASTS = false;
@@ -622,7 +605,7 @@ public class PackageManagerService extends IPackageManager.Stub
/** Suffix of stub packages on the system partition */
public final static String STUB_SUFFIX = "-Stub";
- private static final int[] EMPTY_INT_ARRAY = new int[0];
+ static final int[] EMPTY_INT_ARRAY = new int[0];
/**
* Timeout (in milliseconds) after which the watchdog should declare that
@@ -674,7 +657,7 @@ public class PackageManagerService extends IPackageManager.Stub
* This can be either PackageManager.VERIFICATION_ALLOW or
* PackageManager.VERIFICATION_REJECT.
*/
- private static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW;
+ static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW;
/**
* Adding an installer package name to a package that does not have one set requires the
@@ -769,7 +752,7 @@ public class PackageManagerService extends IPackageManager.Stub
final Handler mHandler;
- private final ProcessLoggingHandler mProcessLoggingHandler;
+ final ProcessLoggingHandler mProcessLoggingHandler;
private final boolean mEnableFreeCacheV2;
@@ -838,7 +821,7 @@ public class PackageManagerService extends IPackageManager.Stub
* find updated user-installed versions. Keys are package name, values
* are package location.
*/
- final private ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
+ final ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
/**
* Tracks existing packages prior to receiving an OTA. Keys are package name.
@@ -857,7 +840,7 @@ public class PackageManagerService extends IPackageManager.Stub
* @see Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL
* @see #systemReady()
*/
- private @Nullable List<File> mReleaseOnSystemReady;
+ @Nullable List<File> mReleaseOnSystemReady;
/**
* Whether or not system app permissions should be promoted from install to runtime.
@@ -900,7 +883,7 @@ public class PackageManagerService extends IPackageManager.Stub
final ArrayMap<String, FeatureInfo> mAvailableFeatures;
@Watched
- private final InstantAppRegistry mInstantAppRegistry;
+ final InstantAppRegistry mInstantAppRegistry;
@GuardedBy("mLock")
int mChangedPackagesSequenceNumber;
@@ -943,7 +926,7 @@ public class PackageManagerService extends IPackageManager.Stub
new ArrayList<>();
// Cached parsed flag value. Invalidated on each flag change.
- private PerUidReadTimeouts[] mPerUidReadTimeoutsCache;
+ PerUidReadTimeouts[] mPerUidReadTimeoutsCache;
private static final PerUidReadTimeouts[] EMPTY_PER_UID_READ_TIMEOUTS_ARRAY = {};
@@ -1441,7 +1424,7 @@ public class PackageManagerService extends IPackageManager.Stub
boolean mResolverReplaced = false;
@NonNull
- private final DomainVerificationManagerInternal mDomainVerificationManager;
+ final DomainVerificationManagerInternal mDomainVerificationManager;
/** The service connection to the ephemeral resolver */
final InstantAppResolverConnection mInstantAppResolverConnection;
@@ -1585,7 +1568,7 @@ public class PackageManagerService extends IPackageManager.Stub
final UserManagerService mUserManager;
// Stores a list of users whose package restrictions file needs to be updated
- private final ArraySet<Integer> mDirtyUsers = new ArraySet<>();
+ final ArraySet<Integer> mDirtyUsers = new ArraySet<>();
// Recordkeeping of restore-after-install operations that are currently in flight
// between the Package Manager and the Backup Manager
@@ -2050,6 +2033,13 @@ public class PackageManagerService extends IPackageManager.Stub
boolean filterAppAccess(int uid, int callingUid);
@LiveImplementation(override = LiveImplementation.MANDATORY)
void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
+ FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent,
+ String resolvedType, int flags, List<ResolveInfo> query, boolean always,
+ boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
+ ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags,
+ List<ResolveInfo> query, boolean debug, int userId);
}
/**
@@ -2858,7 +2848,24 @@ public class PackageManagerService extends IPackageManager.Stub
}
allHomeCandidates.addAll(resolveInfos);
- final String packageName = mDefaultAppProvider.getDefaultHome(userId);
+ String packageName = mDefaultAppProvider.getDefaultHome(userId);
+ if (packageName == null) {
+ // Role changes are not and cannot be atomic because its implementation lives inside
+ // a system app, so when the home role changes, there is a window when the previous
+ // role holder is removed and the new role holder is granted the preferred activity,
+ // but hasn't become the role holder yet. However, this case may be easily hit
+ // because the preferred activity change triggers a broadcast and receivers may try
+ // to get the default home activity there. So we need to fix it for this time
+ // window, and an easy workaround is to fallback to the current preferred activity.
+ final int appId = UserHandle.getAppId(Binder.getCallingUid());
+ final boolean filtered = appId >= Process.FIRST_APPLICATION_UID;
+ FindPreferredActivityBodyResult result = findPreferredActivityInternal(
+ intent, null, 0, resolveInfos, true, false, false, userId, filtered);
+ ResolveInfo preferredResolveInfo = result.mPreferredResolveInfo;
+ if (preferredResolveInfo != null && preferredResolveInfo.activityInfo != null) {
+ packageName = preferredResolveInfo.activityInfo.packageName;
+ }
+ }
if (packageName == null) {
return null;
}
@@ -4610,8 +4617,14 @@ public class PackageManagerService extends IPackageManager.Stub
public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
final String packageName = dumpState.getTargetPackageName();
+ final PackageSetting setting = mSettings.getPackageLPr(packageName);
final boolean checkin = dumpState.isCheckIn();
+ // Return if the package doesn't exist.
+ if (packageName != null && setting == null) {
+ return;
+ }
+
switch (type) {
case DumpState.DUMP_VERSION:
{
@@ -4704,8 +4717,7 @@ public class PackageManagerService extends IPackageManager.Stub
case DumpState.DUMP_QUERIES:
{
- final PackageSetting setting = mSettings.getPackageLPr(packageName);
- Integer filteringAppId = setting == null ? null : setting.appId;
+ final Integer filteringAppId = setting == null ? null : setting.appId;
mAppsFilter.dumpQueries(
pw, filteringAppId, dumpState, mUserManager.getUserIds(),
this::getPackagesForUidInternalBody);
@@ -4716,8 +4728,9 @@ public class PackageManagerService extends IPackageManager.Stub
{
final android.util.IndentingPrintWriter writer =
new android.util.IndentingPrintWriter(pw);
- if (dumpState.onTitlePrinted()) pw.println();
-
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
writer.println("Domain verification status:");
writer.increaseIndent();
try {
@@ -4734,18 +4747,14 @@ public class PackageManagerService extends IPackageManager.Stub
case DumpState.DUMP_DEXOPT:
{
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
- ipw.println();
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
ipw.println("Dexopt state:");
ipw.increaseIndent();
Collection<PackageSetting> pkgSettings;
- if (packageName != null) {
- PackageSetting targetPkgSetting = mSettings.getPackageLPr(packageName);
- if (targetPkgSetting != null) {
- pkgSettings = Collections.singletonList(targetPkgSetting);
- } else {
- ipw.println("Unable to find package: " + packageName);
- return;
- }
+ if (setting != null) {
+ pkgSettings = Collections.singletonList(setting);
} else {
pkgSettings = mSettings.getPackagesLocked().values();
}
@@ -4755,10 +4764,12 @@ public class PackageManagerService extends IPackageManager.Stub
if (pkg == null) {
continue;
}
- ipw.println("[" + pkgSetting.name + "]");
+ final String pkgName = pkg.getPackageName();
+ ipw.println("[" + pkgName + "]");
ipw.increaseIndent();
+
mPackageDexOptimizer.dumpDexoptState(ipw, pkg, pkgSetting,
- mDexManager.getPackageUseInfoOrDefault(pkg.getPackageName()));
+ mDexManager.getPackageUseInfoOrDefault(pkgName));
ipw.decreaseIndent();
}
break;
@@ -4767,28 +4778,29 @@ public class PackageManagerService extends IPackageManager.Stub
case DumpState.DUMP_COMPILER_STATS:
{
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
- ipw.println();
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
ipw.println("Compiler stats:");
ipw.increaseIndent();
- Collection<AndroidPackage> packages;
- if (packageName != null) {
- AndroidPackage targetPackage = mPackages.get(packageName);
- if (targetPackage != null) {
- packages = Collections.singletonList(targetPackage);
- } else {
- ipw.println("Unable to find package: " + packageName);
- return;
- }
+ Collection<PackageSetting> pkgSettings;
+ if (setting != null) {
+ pkgSettings = Collections.singletonList(setting);
} else {
- packages = mPackages.values();
+ pkgSettings = mSettings.getPackagesLocked().values();
}
- for (AndroidPackage pkg : packages) {
+ for (PackageSetting pkgSetting : pkgSettings) {
+ final AndroidPackage pkg = pkgSetting.getPkg();
+ if (pkg == null) {
+ continue;
+ }
final String pkgName = pkg.getPackageName();
ipw.println("[" + pkgName + "]");
ipw.increaseIndent();
- CompilerStats.PackageStats stats = mCompilerStats.getPackageStats(pkgName);
+ final CompilerStats.PackageStats stats =
+ mCompilerStats.getPackageStats(pkgName);
if (stats == null) {
ipw.println("(No recorded stats)");
} else {
@@ -4800,6 +4812,284 @@ public class PackageManagerService extends IPackageManager.Stub
}
} // switch
}
+
+ // The body of findPreferredActivity.
+ protected FindPreferredActivityBodyResult findPreferredActivityBody(
+ Intent intent, String resolvedType, int flags,
+ List<ResolveInfo> query, boolean always,
+ boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
+ int callingUid, boolean isDeviceProvisioned) {
+ FindPreferredActivityBodyResult result = new FindPreferredActivityBodyResult();
+
+ flags = updateFlagsForResolve(
+ flags, userId, callingUid, false /*includeInstantApps*/,
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+ resolvedType, flags));
+ intent = updateIntentForResolve(intent);
+
+ // Try to find a matching persistent preferred activity.
+ result.mPreferredResolveInfo = findPersistentPreferredActivityLP(intent,
+ resolvedType, flags, query, debug, userId);
+
+ // If a persistent preferred activity matched, use it.
+ if (result.mPreferredResolveInfo != null) {
+ return result;
+ }
+
+ PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
+ // Get the list of preferred activities that handle the intent
+ if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
+ List<PreferredActivity> prefs = pir != null
+ ? pir.queryIntent(intent, resolvedType,
+ (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
+ userId)
+ : null;
+ if (prefs != null && prefs.size() > 0) {
+
+ // First figure out how good the original match set is.
+ // We will only allow preferred activities that came
+ // from the same match quality.
+ int match = 0;
+
+ if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match...");
+
+ final int N = query.size();
+ for (int j = 0; j < N; j++) {
+ final ResolveInfo ri = query.get(j);
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Match for " + ri.activityInfo
+ + ": 0x" + Integer.toHexString(match));
+ }
+ if (ri.match > match) {
+ match = ri.match;
+ }
+ }
+
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Best match: 0x" + Integer.toHexString(match));
+ }
+ match &= IntentFilter.MATCH_CATEGORY_MASK;
+ final int M = prefs.size();
+ for (int i = 0; i < M; i++) {
+ final PreferredActivity pa = prefs.get(i);
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Checking PreferredActivity ds="
+ + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>")
+ + "\n component=" + pa.mPref.mComponent);
+ pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
+ }
+ if (pa.mPref.mMatch != match) {
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Skipping bad match "
+ + Integer.toHexString(pa.mPref.mMatch));
+ }
+ continue;
+ }
+ // If it's not an "always" type preferred activity and that's what we're
+ // looking for, skip it.
+ if (always && !pa.mPref.mAlways) {
+ if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry");
+ continue;
+ }
+ final ActivityInfo ai = getActivityInfo(
+ pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS
+ | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+ userId);
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Found preferred activity:");
+ if (ai != null) {
+ ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
+ } else {
+ Slog.v(TAG, " null");
+ }
+ }
+ final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent)
+ && !isDeviceProvisioned;
+ final boolean allowSetMutation = !excludeSetupWizardHomeActivity
+ && !queryMayBeFiltered;
+ if (ai == null) {
+ // Do not remove launcher's preferred activity during SetupWizard
+ // due to it may not install yet
+ if (!allowSetMutation) {
+ continue;
+ }
+
+ // This previously registered preferred activity
+ // component is no longer known. Most likely an update
+ // to the app was installed and in the new version this
+ // component no longer exists. Clean it up by removing
+ // it from the preferred activities list, and skip it.
+ Slog.w(TAG, "Removing dangling preferred activity: "
+ + pa.mPref.mComponent);
+ pir.removeFilter(pa);
+ result.mChanged = true;
+ continue;
+ }
+ for (int j = 0; j < N; j++) {
+ final ResolveInfo ri = query.get(j);
+ if (!ri.activityInfo.applicationInfo.packageName
+ .equals(ai.applicationInfo.packageName)) {
+ continue;
+ }
+ if (!ri.activityInfo.name.equals(ai.name)) {
+ continue;
+ }
+
+ if (removeMatches && allowSetMutation) {
+ pir.removeFilter(pa);
+ result.mChanged = true;
+ if (DEBUG_PREFERRED) {
+ Slog.v(TAG, "Removing match " + pa.mPref.mComponent);
+ }
+ break;
+ }
+
+ // Okay we found a previously set preferred or last chosen app.
+ // If the result set is different from when this
+ // was created, and is not a subset of the preferred set, we need to
+ // clear it and re-ask the user their preference, if we're looking for
+ // an "always" type entry.
+
+ if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) {
+ if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) {
+ if (allowSetMutation) {
+ // some components of the set are no longer present in
+ // the query, but the preferred activity can still be reused
+ if (DEBUG_PREFERRED) {
+ Slog.i(TAG, "Result set changed, but PreferredActivity"
+ + " is still valid as only non-preferred"
+ + " components were removed for " + intent
+ + " type " + resolvedType);
+ }
+ // remove obsolete components and re-add the up-to-date
+ // filter
+ PreferredActivity freshPa = new PreferredActivity(pa,
+ pa.mPref.mMatch,
+ pa.mPref.discardObsoleteComponents(query),
+ pa.mPref.mComponent,
+ pa.mPref.mAlways);
+ pir.removeFilter(pa);
+ pir.addFilter(freshPa);
+ result.mChanged = true;
+ } else {
+ if (DEBUG_PREFERRED) {
+ Slog.i(TAG, "Do not remove preferred activity");
+ }
+ }
+ } else {
+ if (allowSetMutation) {
+ Slog.i(TAG,
+ "Result set changed, dropping preferred activity "
+ + "for " + intent + " type "
+ + resolvedType);
+ if (DEBUG_PREFERRED) {
+ Slog.v(TAG,
+ "Removing preferred activity since set changed "
+ + pa.mPref.mComponent);
+ }
+ pir.removeFilter(pa);
+ // Re-add the filter as a "last chosen" entry (!always)
+ PreferredActivity lastChosen = new PreferredActivity(
+ pa, pa.mPref.mMatch, null, pa.mPref.mComponent,
+ false);
+ pir.addFilter(lastChosen);
+ result.mChanged = true;
+ }
+ result.mPreferredResolveInfo = null;
+ return result;
+ }
+ }
+
+ // Yay! Either the set matched or we're looking for the last chosen
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Returning preferred activity: "
+ + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
+ }
+ result.mPreferredResolveInfo = ri;
+ return result;
+ }
+ }
+ }
+ return result;
+ }
+
+ public final FindPreferredActivityBodyResult findPreferredActivityInternal(
+ Intent intent, String resolvedType, int flags,
+ List<ResolveInfo> query, boolean always,
+ boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
+
+ final int callingUid = Binder.getCallingUid();
+ // Do NOT hold the packages lock; this calls up into the settings provider which
+ // could cause a deadlock.
+ final boolean isDeviceProvisioned =
+ android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1;
+ // Find the preferred activity - the lock is held inside the method.
+ return findPreferredActivityBody(
+ intent, resolvedType, flags, query, always, removeMatches, debug,
+ userId, queryMayBeFiltered, callingUid, isDeviceProvisioned);
+ }
+
+ public final ResolveInfo findPersistentPreferredActivityLP(Intent intent,
+ String resolvedType,
+ int flags, List<ResolveInfo> query, boolean debug, int userId) {
+ final int N = query.size();
+ PersistentPreferredIntentResolver ppir =
+ mSettings.getPersistentPreferredActivities(userId);
+ // Get the list of persistent preferred activities that handle the intent
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Looking for persistent preferred activities...");
+ }
+ List<PersistentPreferredActivity> pprefs = ppir != null
+ ? ppir.queryIntent(intent, resolvedType,
+ (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
+ userId)
+ : null;
+ if (pprefs != null && pprefs.size() > 0) {
+ final int M = pprefs.size();
+ for (int i = 0; i < M; i++) {
+ final PersistentPreferredActivity ppa = pprefs.get(i);
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Checking PersistentPreferredActivity ds="
+ + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "<none>")
+ + "\n component=" + ppa.mComponent);
+ ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
+ }
+ final ActivityInfo ai = getActivityInfo(ppa.mComponent,
+ flags | MATCH_DISABLED_COMPONENTS, userId);
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Found persistent preferred activity:");
+ if (ai != null) {
+ ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
+ } else {
+ Slog.v(TAG, " null");
+ }
+ }
+ if (ai == null) {
+ // This previously registered persistent preferred activity
+ // component is no longer known. Ignore it and do NOT remove it.
+ continue;
+ }
+ for (int j = 0; j < N; j++) {
+ final ResolveInfo ri = query.get(j);
+ if (!ri.activityInfo.applicationInfo.packageName
+ .equals(ai.applicationInfo.packageName)) {
+ continue;
+ }
+ if (!ri.activityInfo.name.equals(ai.name)) {
+ continue;
+ }
+ // Found a persistent preference that can handle the intent.
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Returning persistent preferred activity: "
+ + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
+ }
+ return ri;
+ }
+ }
+ }
+ return null;
+ }
}
/**
@@ -4964,6 +5254,16 @@ public class PackageManagerService extends IPackageManager.Stub
super.dump(type, fd, pw, dumpState);
}
}
+ public final FindPreferredActivityBodyResult findPreferredActivityBody(Intent intent,
+ String resolvedType, int flags, List<ResolveInfo> query, boolean always,
+ boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
+ int callingUid, boolean isDeviceProvisioned) {
+ synchronized (mLock) {
+ return super.findPreferredActivityBody(intent, resolvedType, flags, query, always,
+ removeMatches, debug, userId, queryMayBeFiltered, callingUid,
+ isDeviceProvisioned);
+ }
+ }
}
/**
@@ -5539,6 +5839,28 @@ public class PackageManagerService extends IPackageManager.Stub
current.release();
}
}
+ public final FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent,
+ String resolvedType, int flags, List<ResolveInfo> query, boolean always,
+ boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
+ ThreadComputer current = live();
+ try {
+ return current.mComputer.findPreferredActivityInternal(intent, resolvedType, flags,
+ query, always, removeMatches, debug, userId, queryMayBeFiltered);
+ } finally {
+ current.release();
+ }
+ }
+ public final ResolveInfo findPersistentPreferredActivityLP(Intent intent,
+ String resolvedType, int flags, List<ResolveInfo> query, boolean debug,
+ int userId) {
+ ThreadComputer current = live();
+ try {
+ return current.mComputer.findPersistentPreferredActivityLP(intent, resolvedType,
+ flags, query, debug, userId);
+ } finally {
+ current.release();
+ }
+ }
}
@@ -5562,7 +5884,7 @@ public class PackageManagerService extends IPackageManager.Stub
// If true, the snapshot is corked. Do not create a new snapshot but use the live
// computer. This throttles snapshot creation during periods of churn in Package
// Manager.
- private static final AtomicInteger sSnapshotCorked = new AtomicInteger(0);
+ static final AtomicInteger sSnapshotCorked = new AtomicInteger(0);
/**
* This class records the Computer being used by a thread and the Computer's reference
@@ -5736,665 +6058,8 @@ public class PackageManagerService extends IPackageManager.Stub
onChange(null);
}
- class PackageHandler extends Handler {
-
- PackageHandler(Looper looper) {
- super(looper);
- }
-
- public void handleMessage(Message msg) {
- try {
- doHandleMessage(msg);
- } finally {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- }
- }
-
- void doHandleMessage(Message msg) {
- switch (msg.what) {
- case INIT_COPY: {
- HandlerParams params = (HandlerParams) msg.obj;
- if (params != null) {
- if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
- System.identityHashCode(params));
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
- params.startCopy();
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- break;
- }
- case SEND_PENDING_BROADCAST: {
- String[] packages;
- ArrayList<String>[] components;
- int size = 0;
- int[] uids;
- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- synchronized (mLock) {
- size = mPendingBroadcasts.size();
- if (size <= 0) {
- // Nothing to be done. Just return
- return;
- }
- packages = new String[size];
- components = new ArrayList[size];
- uids = new int[size];
- int i = 0; // filling out the above arrays
-
- for (int n = 0; n < mPendingBroadcasts.userIdCount(); n++) {
- final int packageUserId = mPendingBroadcasts.userIdAt(n);
- final ArrayMap<String, ArrayList<String>> componentsToBroadcast =
- mPendingBroadcasts.packagesForUserId(packageUserId);
- final int numComponents = componentsToBroadcast.size();
- for (int index = 0; i < size && index < numComponents; index++) {
- packages[i] = componentsToBroadcast.keyAt(index);
- components[i] = componentsToBroadcast.valueAt(index);
- final PackageSetting ps = mSettings.getPackageLPr(packages[i]);
- uids[i] = (ps != null)
- ? UserHandle.getUid(packageUserId, ps.appId)
- : -1;
- i++;
- }
- }
- size = i;
- mPendingBroadcasts.clear();
- }
- // Send broadcasts
- for (int i = 0; i < size; i++) {
- sendPackageChangedBroadcast(packages[i], true /* dontKillApp */,
- components[i], uids[i], null /* reason */);
- }
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- break;
- }
- case POST_INSTALL: {
- if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
-
- PostInstallData data = mRunningInstalls.get(msg.arg1);
- final boolean didRestore = (msg.arg2 != 0);
- mRunningInstalls.delete(msg.arg1);
-
- if (data != null && data.res.mFreezer != null) {
- data.res.mFreezer.close();
- }
-
- if (data != null && data.mPostInstallRunnable != null) {
- data.mPostInstallRunnable.run();
- } else if (data != null && data.args != null) {
- InstallArgs args = data.args;
- PackageInstalledInfo parentRes = data.res;
-
- final boolean killApp = (args.mInstallFlags
- & PackageManager.INSTALL_DONT_KILL_APP) == 0;
- final boolean virtualPreload = ((args.mInstallFlags
- & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
-
- handlePackagePostInstall(parentRes, killApp, virtualPreload,
- didRestore, args.mInstallSource.installerPackageName,
- args.mObserver, args.mDataLoaderType);
-
- // Log tracing if needed
- if (args.mTraceMethod != null) {
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.mTraceMethod,
- args.mTraceCookie);
- }
- } else if (DEBUG_INSTALL) {
- // No post-install when we run restore from installExistingPackageForUser
- Slog.i(TAG, "Nothing to do for post-install token " + msg.arg1);
- }
-
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
- } break;
- case DEFERRED_NO_KILL_POST_DELETE: {
- synchronized (mInstallLock) {
- InstallArgs args = (InstallArgs) msg.obj;
- if (args != null) {
- args.doPostDeleteLI(true);
- }
- }
- } break;
- case DEFERRED_NO_KILL_INSTALL_OBSERVER: {
- String packageName = (String) msg.obj;
- if (packageName != null) {
- notifyInstallObserver(packageName);
- }
- } break;
- case WRITE_SETTINGS: {
- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- synchronized (mLock) {
- removeMessages(WRITE_SETTINGS);
- removeMessages(WRITE_PACKAGE_RESTRICTIONS);
- writeSettingsLPrTEMP();
- mDirtyUsers.clear();
- }
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- } break;
- case WRITE_PACKAGE_RESTRICTIONS: {
- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- synchronized (mLock) {
- removeMessages(WRITE_PACKAGE_RESTRICTIONS);
- for (int userId : mDirtyUsers) {
- mSettings.writePackageRestrictionsLPr(userId);
- }
- mDirtyUsers.clear();
- }
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- } break;
- case WRITE_PACKAGE_LIST: {
- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- synchronized (mLock) {
- removeMessages(WRITE_PACKAGE_LIST);
- mSettings.writePackageListLPr(msg.arg1);
- }
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- } break;
- case CHECK_PENDING_VERIFICATION: {
- final int verificationId = msg.arg1;
- final PackageVerificationState state = mPendingVerification.get(verificationId);
-
- if ((state != null) && !state.isVerificationComplete()
- && !state.timeoutExtended()) {
- final VerificationParams params = state.getVerificationParams();
- final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
-
- String errorMsg = "Verification timed out for " + originUri;
- Slog.i(TAG, errorMsg);
-
- final UserHandle user = params.getUser();
- if (getDefaultVerificationResponse(user)
- == PackageManager.VERIFICATION_ALLOW) {
- Slog.i(TAG, "Continuing with installation of " + originUri);
- state.setVerifierResponse(Binder.getCallingUid(),
- PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
- broadcastPackageVerified(verificationId, originUri,
- PackageManager.VERIFICATION_ALLOW, null, params.mDataLoaderType,
- user);
- } else {
- broadcastPackageVerified(verificationId, originUri,
- PackageManager.VERIFICATION_REJECT, null,
- params.mDataLoaderType, user);
- params.setReturnCode(
- PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg);
- state.setVerifierResponse(Binder.getCallingUid(),
- PackageManager.VERIFICATION_REJECT);
- }
-
- if (state.areAllVerificationsComplete()) {
- mPendingVerification.remove(verificationId);
- }
-
- Trace.asyncTraceEnd(
- TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
-
- params.handleVerificationFinished();
-
- }
- break;
- }
- case CHECK_PENDING_INTEGRITY_VERIFICATION: {
- final int verificationId = msg.arg1;
- final PackageVerificationState state = mPendingVerification.get(verificationId);
-
- if (state != null && !state.isIntegrityVerificationComplete()) {
- final VerificationParams params = state.getVerificationParams();
- final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
-
- String errorMsg = "Integrity verification timed out for " + originUri;
- Slog.i(TAG, errorMsg);
-
- state.setIntegrityVerificationResult(
- getDefaultIntegrityVerificationResponse());
-
- if (getDefaultIntegrityVerificationResponse()
- == PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) {
- Slog.i(TAG, "Integrity check times out, continuing with " + originUri);
- } else {
- params.setReturnCode(
- PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
- errorMsg);
- }
-
- if (state.areAllVerificationsComplete()) {
- mPendingVerification.remove(verificationId);
- }
-
- Trace.asyncTraceEnd(
- TRACE_TAG_PACKAGE_MANAGER,
- "integrity_verification",
- verificationId);
-
- params.handleIntegrityVerificationFinished();
- }
- break;
- }
- case PACKAGE_VERIFIED: {
- final int verificationId = msg.arg1;
-
- final PackageVerificationState state = mPendingVerification.get(verificationId);
- if (state == null) {
- Slog.w(TAG, "Verification with id " + verificationId
- + " not found."
- + " It may be invalid or overridden by integrity verification");
- break;
- }
-
- final PackageVerificationResponse response = (PackageVerificationResponse) msg.obj;
-
- state.setVerifierResponse(response.callerUid, response.code);
-
- if (state.isVerificationComplete()) {
- final VerificationParams params = state.getVerificationParams();
- final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
-
- if (state.isInstallAllowed()) {
- broadcastPackageVerified(verificationId, originUri,
- response.code, null, params.mDataLoaderType, params.getUser());
- } else {
- params.setReturnCode(
- PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
- "Install not allowed");
- }
-
- if (state.areAllVerificationsComplete()) {
- mPendingVerification.remove(verificationId);
- }
-
- Trace.asyncTraceEnd(
- TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
-
- params.handleVerificationFinished();
- }
-
- break;
- }
- case INTEGRITY_VERIFICATION_COMPLETE: {
- final int verificationId = msg.arg1;
-
- final PackageVerificationState state = mPendingVerification.get(verificationId);
- if (state == null) {
- Slog.w(TAG, "Integrity verification with id " + verificationId
- + " not found. It may be invalid or overridden by verifier");
- break;
- }
-
- final int response = (Integer) msg.obj;
- final VerificationParams params = state.getVerificationParams();
- final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
-
- state.setIntegrityVerificationResult(response);
-
- if (response == PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) {
- Slog.i(TAG, "Integrity check passed for " + originUri);
- } else {
- params.setReturnCode(
- PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
- "Integrity check failed for " + originUri);
- }
-
- if (state.areAllVerificationsComplete()) {
- mPendingVerification.remove(verificationId);
- }
-
- Trace.asyncTraceEnd(
- TRACE_TAG_PACKAGE_MANAGER,
- "integrity_verification",
- verificationId);
-
- params.handleIntegrityVerificationFinished();
- break;
- }
- case INSTANT_APP_RESOLUTION_PHASE_TWO: {
- InstantAppResolver.doInstantAppResolutionPhaseTwo(mContext,
- mInstantAppResolverConnection,
- (InstantAppRequest) msg.obj,
- mInstantAppInstallerActivity,
- mHandler);
- break;
- }
- case ENABLE_ROLLBACK_STATUS: {
- final int enableRollbackToken = msg.arg1;
- final int enableRollbackCode = msg.arg2;
- final VerificationParams params =
- mPendingEnableRollback.get(enableRollbackToken);
- if (params == null) {
- Slog.w(TAG, "Invalid rollback enabled token "
- + enableRollbackToken + " received");
- break;
- }
-
- mPendingEnableRollback.remove(enableRollbackToken);
-
- if (enableRollbackCode != PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED) {
- final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
- Slog.w(TAG, "Failed to enable rollback for " + originUri);
- Slog.w(TAG, "Continuing with installation of " + originUri);
- }
-
- Trace.asyncTraceEnd(
- TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
-
- params.handleRollbackEnabled();
- break;
- }
- case ENABLE_ROLLBACK_TIMEOUT: {
- final int enableRollbackToken = msg.arg1;
- final int sessionId = msg.arg2;
- final VerificationParams params =
- mPendingEnableRollback.get(enableRollbackToken);
- if (params != null) {
- final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
-
- Slog.w(TAG, "Enable rollback timed out for " + originUri);
- mPendingEnableRollback.remove(enableRollbackToken);
-
- Slog.w(TAG, "Continuing with installation of " + originUri);
- Trace.asyncTraceEnd(
- TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
- params.handleRollbackEnabled();
- Intent rollbackTimeoutIntent = new Intent(
- Intent.ACTION_CANCEL_ENABLE_ROLLBACK);
- rollbackTimeoutIntent.putExtra(
- PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
- sessionId);
- rollbackTimeoutIntent.addFlags(
- Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcastAsUser(rollbackTimeoutIntent, UserHandle.SYSTEM,
- android.Manifest.permission.PACKAGE_ROLLBACK_AGENT);
- }
- break;
- }
- case DOMAIN_VERIFICATION: {
- int messageCode = msg.arg1;
- Object object = msg.obj;
- mDomainVerificationManager.runMessage(messageCode, object);
- break;
- }
- case SNAPSHOT_UNCORK: {
- int corking = sSnapshotCorked.decrementAndGet();
- if (TRACE_SNAPSHOTS && corking == 0) {
- Log.e(TAG, "snapshot: corking goes to zero in message handler");
- }
- break;
- }
- }
- }
- }
-
- private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp,
- boolean virtualPreload, boolean launchedForRestore, String installerPackage,
- IPackageInstallObserver2 installObserver, int dataLoaderType) {
- boolean succeeded = res.mReturnCode == PackageManager.INSTALL_SUCCEEDED;
- final boolean update = res.mRemovedInfo != null && res.mRemovedInfo.mRemovedPackage != null;
- final String packageName = res.mName;
- final PackageSetting pkgSetting = succeeded ? getPackageSetting(packageName) : null;
- final boolean removedBeforeUpdate = (pkgSetting == null)
- || (pkgSetting.isSystem() && !pkgSetting.getPathString().equals(
- res.mPkg.getPath()));
- if (succeeded && removedBeforeUpdate) {
- Slog.e(TAG, packageName + " was removed before handlePackagePostInstall "
- + "could be executed");
- res.mReturnCode = INSTALL_FAILED_PACKAGE_CHANGED;
- res.mReturnMsg = "Package was removed before install could complete.";
-
- // Remove the update failed package's older resources safely now
- InstallArgs args = res.mRemovedInfo != null ? res.mRemovedInfo.mArgs : null;
- if (args != null) {
- synchronized (mInstallLock) {
- args.doPostDeleteLI(true);
- }
- }
- notifyInstallObserver(res, installObserver);
- return;
- }
-
- if (succeeded) {
- // Clear the uid cache after we installed a new package.
- mPerUidReadTimeoutsCache = null;
- // Send the removed broadcasts
- if (res.mRemovedInfo != null) {
- res.mRemovedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
- }
- final String installerPackageName =
- res.mInstallerPackageName != null
- ? res.mInstallerPackageName
- : res.mRemovedInfo != null
- ? res.mRemovedInfo.mInstallerPackageName
- : null;
-
- synchronized (mLock) {
- mInstantAppRegistry.onPackageInstalledLPw(res.mPkg, res.mNewUsers);
- }
-
- // Determine the set of users who are adding this package for
- // the first time vs. those who are seeing an update.
- int[] firstUserIds = EMPTY_INT_ARRAY;
- int[] firstInstantUserIds = EMPTY_INT_ARRAY;
- int[] updateUserIds = EMPTY_INT_ARRAY;
- int[] instantUserIds = EMPTY_INT_ARRAY;
- final boolean allNewUsers = res.mOrigUsers == null || res.mOrigUsers.length == 0;
- for (int newUser : res.mNewUsers) {
- final boolean isInstantApp = pkgSetting.getInstantApp(newUser);
- if (allNewUsers) {
- if (isInstantApp) {
- firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
- } else {
- firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
- }
- continue;
- }
- boolean isNew = true;
- for (int origUser : res.mOrigUsers) {
- if (origUser == newUser) {
- isNew = false;
- break;
- }
- }
- if (isNew) {
- if (isInstantApp) {
- firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
- } else {
- firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
- }
- } else {
- if (isInstantApp) {
- instantUserIds = ArrayUtils.appendInt(instantUserIds, newUser);
- } else {
- updateUserIds = ArrayUtils.appendInt(updateUserIds, newUser);
- }
- }
- }
-
- // Send installed broadcasts if the package is not a static shared lib.
- if (res.mPkg.getStaticSharedLibName() == null) {
- mProcessLoggingHandler.invalidateBaseApkHash(res.mPkg.getBaseApkPath());
-
- // Send added for users that see the package for the first time
- // sendPackageAddedForNewUsers also deals with system apps
- int appId = UserHandle.getAppId(res.mUid);
- boolean isSystem = res.mPkg.isSystem();
- sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
- virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds,
- dataLoaderType);
-
- // Send added for users that don't see the package for the first time
- Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, res.mUid);
- if (update) {
- extras.putBoolean(Intent.EXTRA_REPLACING, true);
- }
- extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
- // Send to all running apps.
- final SparseArray<int[]> newBroadcastAllowList;
-
- synchronized (mLock) {
- newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
- getPackageSettingInternal(res.mName, Process.SYSTEM_UID),
- updateUserIds, mSettings.getPackagesLocked());
- }
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
- extras, 0 /*flags*/,
- null /*targetPackage*/, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, newBroadcastAllowList, null);
- if (installerPackageName != null) {
- // Send to the installer, even if it's not running.
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
- extras, 0 /*flags*/,
- installerPackageName, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
- }
- // if the required verifier is defined, but, is not the installer of record
- // for the package, it gets notified
- final boolean notifyVerifier = mRequiredVerifierPackage != null
- && !mRequiredVerifierPackage.equals(installerPackageName);
- if (notifyVerifier) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
- extras, 0 /*flags*/,
- mRequiredVerifierPackage, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
- }
- // If package installer is defined, notify package installer about new
- // app installed
- if (mRequiredInstallerPackage != null) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
- extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND /*flags*/,
- mRequiredInstallerPackage, null /*finishedReceiver*/,
- firstUserIds, instantUserIds, null /* broadcastAllowList */, null);
- }
-
- // Send replaced for users that don't see the package for the first time
- if (update) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- packageName, extras, 0 /*flags*/,
- null /*targetPackage*/, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, res.mRemovedInfo.mBroadcastAllowList,
- null);
- if (installerPackageName != null) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
- extras, 0 /*flags*/,
- installerPackageName, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, null /*broadcastAllowList*/, null);
- }
- if (notifyVerifier) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
- extras, 0 /*flags*/,
- mRequiredVerifierPackage, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, null /*broadcastAllowList*/, null);
- }
- sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
- null /*package*/, null /*extras*/, 0 /*flags*/,
- packageName /*targetPackage*/,
- null /*finishedReceiver*/, updateUserIds, instantUserIds,
- null /*broadcastAllowList*/,
- getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED)
- .toBundle());
- } else if (launchedForRestore && !res.mPkg.isSystem()) {
- // First-install and we did a restore, so we're responsible for the
- // first-launch broadcast.
- if (DEBUG_BACKUP) {
- Slog.i(TAG, "Post-restore of " + packageName
- + " sending FIRST_LAUNCH in " + Arrays.toString(firstUserIds));
- }
- sendFirstLaunchBroadcast(packageName, installerPackage,
- firstUserIds, firstInstantUserIds);
- }
-
- // Send broadcast package appeared if external for all users
- if (res.mPkg.isExternalStorage()) {
- if (!update) {
- final StorageManager storage = mInjector.getSystemService(
- StorageManager.class);
- VolumeInfo volume =
- storage.findVolumeByUuid(
- res.mPkg.getStorageUuid().toString());
- int packageExternalStorageType =
- getPackageExternalStorageType(volume, res.mPkg.isExternalStorage());
- // If the package was installed externally, log it.
- if (packageExternalStorageType != StorageEnums.UNKNOWN) {
- FrameworkStatsLog.write(
- FrameworkStatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
- packageExternalStorageType, packageName);
- }
- }
- if (DEBUG_INSTALL) {
- Slog.i(TAG, "upgrading pkg " + res.mPkg + " is external");
- }
- final int[] uidArray = new int[]{res.mPkg.getUid()};
- ArrayList<String> pkgList = new ArrayList<>(1);
- pkgList.add(packageName);
- sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
- }
- } else if (!ArrayUtils.isEmpty(res.mLibraryConsumers)) { // if static shared lib
- for (int i = 0; i < res.mLibraryConsumers.size(); i++) {
- AndroidPackage pkg = res.mLibraryConsumers.get(i);
- // send broadcast that all consumers of the static shared library have changed
- sendPackageChangedBroadcast(pkg.getPackageName(), false /* dontKillApp */,
- new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
- pkg.getUid(), null);
- }
- }
-
- // Work that needs to happen on first install within each user
- if (firstUserIds != null && firstUserIds.length > 0) {
- for (int userId : firstUserIds) {
- restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
- userId);
- }
- }
-
- if (allNewUsers && !update) {
- notifyPackageAdded(packageName, res.mUid);
- } else {
- notifyPackageChanged(packageName, res.mUid);
- }
-
- // Log current value of "unknown sources" setting
- EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
- getUnknownSourcesSettings());
-
- // Remove the replaced package's older resources safely now
- InstallArgs args = res.mRemovedInfo != null ? res.mRemovedInfo.mArgs : null;
- if (args != null) {
- if (!killApp) {
- // If we didn't kill the app, defer the deletion of code/resource files, since
- // they may still be in use by the running application. This mitigates problems
- // in cases where resources or code is loaded by a new Activity before
- // ApplicationInfo changes have propagated to all application threads.
- scheduleDeferredNoKillPostDelete(args);
- } else {
- synchronized (mInstallLock) {
- args.doPostDeleteLI(true);
- }
- }
- } else {
- // Force a gc to clear up things. Ask for a background one, it's fine to go on
- // and not block here.
- VMRuntime.getRuntime().requestConcurrentGC();
- }
-
- // Notify DexManager that the package was installed for new users.
- // The updated users should already be indexed and the package code paths
- // should not change.
- // Don't notify the manager for ephemeral apps as they are not expected to
- // survive long enough to benefit of background optimizations.
- for (int userId : firstUserIds) {
- PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
- // There's a race currently where some install events may interleave with an
- // uninstall. This can lead to package info being null (b/36642664).
- if (info != null) {
- mDexManager.notifyPackageInstalled(info, userId);
- }
- }
- }
-
- final boolean deferInstallObserver = succeeded && update && !killApp;
- if (deferInstallObserver) {
- scheduleDeferredNoKillInstallObserver(res, installObserver);
- } else {
- notifyInstallObserver(res, installObserver);
- }
- }
@Override
public void notifyPackagesReplacedReceived(String[] packages) {
@@ -6435,12 +6100,12 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private void scheduleDeferredNoKillPostDelete(InstallArgs args) {
+ void scheduleDeferredNoKillPostDelete(InstallArgs args) {
Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_POST_DELETE, args);
mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_POST_DELETE_DELAY_MS);
}
- private void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info,
+ void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info,
IPackageInstallObserver2 observer) {
String packageName = info.mPkg.getPackageName();
mNoKillInstallObservers.put(packageName, Pair.create(info, observer));
@@ -6528,7 +6193,7 @@ public class PackageManagerService extends IPackageManager.Stub
* corresponding {@link StorageEnums} storage type value if it is.
* corresponding {@link StorageEnums} storage type value if it is.
*/
- private static int getPackageExternalStorageType(VolumeInfo packageVolume,
+ static int getPackageExternalStorageType(VolumeInfo packageVolume,
boolean packageIsExternal) {
if (packageVolume != null) {
DiskInfo disk = packageVolume.getDisk();
@@ -6723,7 +6388,7 @@ public class PackageManagerService extends IPackageManager.Stub
HandlerThread thread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
thread.start();
- return pm.new PackageHandler(thread.getLooper());
+ return new PackageHandler(thread.getLooper(), pm);
},
new DefaultSystemWrapper(),
LocalServices::getService,
@@ -6829,53 +6494,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @VisibleForTesting
- public static class ScanPartition extends SystemPartition {
- @ScanFlags
- public final int scanFlag;
-
- public ScanPartition(@NonNull SystemPartition partition) {
- super(partition);
- scanFlag = scanFlagForPartition(partition);
- }
-
- /**
- * Creates a partition containing the same folders as the original partition but with a
- * different root folder. The new partition will include the scan flags of the original
- * partition along with any specified additional scan flags.
- */
- public ScanPartition(@NonNull File folder, @NonNull ScanPartition original,
- @ScanFlags int additionalScanFlag) {
- super(folder, original);
- this.scanFlag = original.scanFlag | additionalScanFlag;
- }
-
- private static int scanFlagForPartition(PackagePartitions.SystemPartition partition) {
- switch (partition.type) {
- case PackagePartitions.PARTITION_SYSTEM:
- return 0;
- case PackagePartitions.PARTITION_VENDOR:
- return SCAN_AS_VENDOR;
- case PackagePartitions.PARTITION_ODM:
- return SCAN_AS_ODM;
- case PackagePartitions.PARTITION_OEM:
- return SCAN_AS_OEM;
- case PackagePartitions.PARTITION_PRODUCT:
- return SCAN_AS_PRODUCT;
- case PackagePartitions.PARTITION_SYSTEM_EXT:
- return SCAN_AS_SYSTEM_EXT;
- default:
- throw new IllegalStateException("Unable to determine scan flag for "
- + partition.getFolder());
- }
- }
-
- @Override
- public String toString() {
- return getFolder().getAbsolutePath() + ":" + scanFlag;
- }
- }
-
// Link watchables to the class
private void registerObserver() {
mPackages.registerObserver(mWatcher);
@@ -7215,7 +6833,6 @@ public class PackageManagerService extends IPackageManager.Stub
Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
}
- File frameworkDir = new File(Environment.getRootDirectory(), "framework");
final VersionInfo ver = mSettings.getInternalVersion();
mIsUpgrade =
@@ -7267,286 +6884,23 @@ public class PackageManagerService extends IPackageManager.Stub
// Prepare apex package info before scanning APKs, these information are needed when
// scanning apk in apex.
mApexManager.scanApexPackagesTraced(packageParser, executorService);
- // Collect vendor/product/system_ext overlay packages. (Do this before scanning
- // any apps.)
- // For security and version matching reason, only consider overlay packages if they
- // reside in the right directory.
- for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
- final ScanPartition partition = mDirsToScanAsSystem.get(i);
- if (partition.getOverlayFolder() == null) {
- continue;
- }
- scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags,
- systemScanFlags | partition.scanFlag, 0,
- packageParser, executorService);
- }
-
- scanDirTracedLI(frameworkDir, systemParseFlags,
- systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
- packageParser, executorService);
- if (!mPackages.containsKey("android")) {
- throw new IllegalStateException(
- "Failed to load frameworks package; check log for warnings");
- }
- for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
- final ScanPartition partition = mDirsToScanAsSystem.get(i);
- if (partition.getPrivAppFolder() != null) {
- scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags,
- systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
- packageParser, executorService);
- }
- scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
- systemScanFlags | partition.scanFlag, 0,
- packageParser, executorService);
- }
+ final InitAndSystemPackageHelper helper = new InitAndSystemPackageHelper(this);
+ helper.scanSystemDirs(mDirsToScanAsSystem, mIsUpgrade,
+ packageParser, executorService, mPlatformPackage, mIsPreNMR1Upgrade,
+ systemParseFlags, systemScanFlags);
// Parse overlay configuration files to set default enable state, mutability, and
// priority of system overlays.
mOverlayConfig = OverlayConfig.initializeSystemInstance(
consumer -> mPmInternal.forEachPackage(
pkg -> consumer.accept(pkg, pkg.isSystem())));
-
- // Prune any system packages that no longer exist.
- final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
- // Stub packages must either be replaced with full versions in the /data
- // partition or be disabled.
- final List<String> stubSystemApps = new ArrayList<>();
final int[] userIds = mUserManager.getUserIds();
- if (!mOnlyCore) {
- // do this first before mucking with mPackages for the "expecting better" case
- final int numPackages = mPackages.size();
- for (int index = 0; index < numPackages; index++) {
- final AndroidPackage pkg = mPackages.valueAt(index);
- if (pkg.isStub()) {
- stubSystemApps.add(pkg.getPackageName());
- }
- }
-
- // Iterates PackageSettings in reversed order because the item could be removed
- // during the iteration.
- for (int index = packageSettings.size() - 1; index >= 0; index--) {
- final PackageSetting ps = packageSettings.valueAt(index);
-
- /*
- * If this is not a system app, it can't be a
- * disable system app.
- */
- if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
- continue;
- }
-
- /*
- * If the package is scanned, it's not erased.
- */
- final AndroidPackage scannedPkg = mPackages.get(ps.name);
- if (scannedPkg != null) {
- /*
- * If the system app is both scanned and in the
- * disabled packages list, then it must have been
- * added via OTA. Remove it from the currently
- * scanned package so the previously user-installed
- * application can be scanned.
- */
- if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
- logCriticalInfo(Log.WARN,
- "Expecting better updated system app for " + ps.name
- + "; removing system app. Last known"
- + " codePath=" + ps.getPathString()
- + ", versionCode=" + ps.versionCode
- + "; scanned versionCode=" + scannedPkg.getLongVersionCode());
- removePackageLI(scannedPkg, true);
- mExpectingBetter.put(ps.name, ps.getPath());
- }
-
- continue;
- }
-
- if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
- logCriticalInfo(Log.WARN, "System package " + ps.name
- + " no longer exists; its data will be wiped");
- removePackageDataLIF(ps, userIds, null, 0, false);
- } else {
- // we still have a disabled system package, but, it still might have
- // been removed. check the code path still exists and check there's
- // still a package. the latter can happen if an OTA keeps the same
- // code path, but, changes the package name.
- final PackageSetting disabledPs =
- mSettings.getDisabledSystemPkgLPr(ps.name);
- if (disabledPs.getPath() == null || !disabledPs.getPath().exists()
- || disabledPs.pkg == null) {
- possiblyDeletedUpdatedSystemApps.add(ps.name);
- } else {
- // We're expecting that the system app should remain disabled, but add
- // it to expecting better to recover in case the data version cannot
- // be scanned.
- mExpectingBetter.put(disabledPs.name, disabledPs.getPath());
- }
- }
- }
- }
-
- final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
-
- // Remove any shared userIDs that have no associated packages
- mSettings.pruneSharedUsersLPw();
- final long systemScanTime = SystemClock.uptimeMillis() - startTime;
- final int systemPackagesCount = mPackages.size();
- Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
- + " ms, packageCount: " + systemPackagesCount
- + " , timePerPackage: "
- + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
- + " , cached: " + cachedSystemApps);
- if (mIsUpgrade && systemPackagesCount > 0) {
- //CHECKSTYLE:OFF IndentationCheck
- FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
- BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
- systemScanTime / systemPackagesCount);
- //CHECKSTYLE:ON IndentationCheck
- }
- if (!mOnlyCore) {
- EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
- SystemClock.uptimeMillis());
- scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
- packageParser, executorService);
-
- }
-
+ helper.cleanupSystemPackagesAndInstallStubs(mDirsToScanAsSystem,
+ mIsUpgrade, packageParser, executorService, mOnlyCore, packageSettings,
+ startTime, mAppInstallDir, mPlatformPackage, mIsPreNMR1Upgrade,
+ scanFlags, systemParseFlags, systemScanFlags, userIds);
packageParser.close();
- List<Runnable> unfinishedTasks = executorService.shutdownNow();
- if (!unfinishedTasks.isEmpty()) {
- throw new IllegalStateException("Not all tasks finished before calling close: "
- + unfinishedTasks);
- }
-
- if (!mOnlyCore) {
- // Remove disable package settings for updated system apps that were
- // removed via an OTA. If the update is no longer present, remove the
- // app completely. Otherwise, revoke their system privileges.
- for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
- final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
- final AndroidPackage pkg = mPackages.get(packageName);
- final String msg;
-
- // remove from the disabled system list; do this first so any future
- // scans of this package are performed without this state
- mSettings.removeDisabledSystemPackageLPw(packageName);
-
- if (pkg == null) {
- // should have found an update, but, we didn't; remove everything
- msg = "Updated system package " + packageName
- + " no longer exists; removing its data";
- // Actual deletion of code and data will be handled by later
- // reconciliation step
- } else {
- // found an update; revoke system privileges
- msg = "Updated system package " + packageName
- + " no longer exists; rescanning package on data";
-
- // NOTE: We don't do anything special if a stub is removed from the
- // system image. But, if we were [like removing the uncompressed
- // version from the /data partition], this is where it'd be done.
-
- // remove the package from the system and re-scan it without any
- // special privileges
- removePackageLI(pkg, true);
- try {
- final File codePath = new File(pkg.getPath());
- scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
- } catch (PackageManagerException e) {
- Slog.e(TAG, "Failed to parse updated, ex-system package: "
- + e.getMessage());
- }
- }
-
- // one final check. if we still have a package setting [ie. it was
- // previously scanned and known to the system], but, we don't have
- // a package [ie. there was an error scanning it from the /data
- // partition], completely remove the package data.
- final PackageSetting ps = mSettings.getPackageLPr(packageName);
- if (ps != null && mPackages.get(packageName) == null) {
- removePackageDataLIF(ps, userIds, null, 0, false);
-
- }
- logCriticalInfo(Log.WARN, msg);
- }
-
- /*
- * Make sure all system apps that we expected to appear on
- * the userdata partition actually showed up. If they never
- * appeared, crawl back and revive the system version.
- */
- for (int i = 0; i < mExpectingBetter.size(); i++) {
- final String packageName = mExpectingBetter.keyAt(i);
- if (!mPackages.containsKey(packageName)) {
- final File scanFile = mExpectingBetter.valueAt(i);
-
- logCriticalInfo(Log.WARN, "Expected better " + packageName
- + " but never showed up; reverting to system");
-
- @ParseFlags int reparseFlags = 0;
- @ScanFlags int rescanFlags = 0;
- for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
- final ScanPartition partition = mDirsToScanAsSystem.get(i1);
- if (partition.containsPrivApp(scanFile)) {
- reparseFlags = systemParseFlags;
- rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED
- | partition.scanFlag;
- break;
- }
- if (partition.containsApp(scanFile)) {
- reparseFlags = systemParseFlags;
- rescanFlags = systemScanFlags | partition.scanFlag;
- break;
- }
- }
- if (rescanFlags == 0) {
- Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
- continue;
- }
- mSettings.enableSystemPackageLPw(packageName);
-
- try {
- final AndroidPackage newPkg = scanPackageTracedLI(
- scanFile, reparseFlags, rescanFlags, 0, null);
- // We rescanned a stub, add it to the list of stubbed system packages
- if (newPkg.isStub()) {
- stubSystemApps.add(packageName);
- }
- } catch (PackageManagerException e) {
- Slog.e(TAG, "Failed to parse original system package: "
- + e.getMessage());
- }
- }
- }
-
- // Uncompress and install any stubbed system applications.
- // This must be done last to ensure all stubs are replaced or disabled.
- installSystemStubPackages(stubSystemApps, scanFlags);
-
- final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
- - cachedSystemApps;
-
- final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
- final int dataPackagesCount = mPackages.size() - systemPackagesCount;
- Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
- + " ms, packageCount: " + dataPackagesCount
- + " , timePerPackage: "
- + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
- + " , cached: " + cachedNonSystemApps);
- if (mIsUpgrade && dataPackagesCount > 0) {
- //CHECKSTYLE:OFF IndentationCheck
- FrameworkStatsLog.write(
- FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
- BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
- dataScanTime / dataPackagesCount);
- //CHECKSTYLE:OFF IndentationCheck
- }
- }
- mExpectingBetter.clear();
-
- mSettings.pruneRenamedPackagesLPw();
-
// Resolve the storage manager.
mStorageManagerPackage = getStorageManagerPackageName();
@@ -7637,7 +6991,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
List<String> deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL,
UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */,
- true /* onlyCoreApps */);
+ true /* onlyCoreApps */, null);
mPrepareAppDataFuture = SystemServerInitThreadPool.submit(() -> {
TimingsTraceLog traceLog = new TimingsTraceLog("SystemServerTimingAsync",
Trace.TRACE_TAG_PACKAGE_MANAGER);
@@ -7840,234 +7194,10 @@ public class PackageManagerService extends IPackageManager.Stub
Slog.i(TAG, "Fix for b/169414761 is applied");
}
- /**
- * Uncompress and install stub applications.
- * <p>In order to save space on the system partition, some applications are shipped in a
- * compressed form. In addition the compressed bits for the full application, the
- * system image contains a tiny stub comprised of only the Android manifest.
- * <p>During the first boot, attempt to uncompress and install the full application. If
- * the application can't be installed for any reason, disable the stub and prevent
- * uncompressing the full application during future boots.
- * <p>In order to forcefully attempt an installation of a full application, go to app
- * settings and enable the application.
- */
- private void installSystemStubPackages(@NonNull List<String> systemStubPackageNames,
- @ScanFlags int scanFlags) {
- for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
- final String packageName = systemStubPackageNames.get(i);
- // skip if the system package is already disabled
- if (mSettings.isDisabledSystemPackageLPr(packageName)) {
- systemStubPackageNames.remove(i);
- continue;
- }
- // skip if the package isn't installed (?!); this should never happen
- final AndroidPackage pkg = mPackages.get(packageName);
- if (pkg == null) {
- systemStubPackageNames.remove(i);
- continue;
- }
- // skip if the package has been disabled by the user
- final PackageSetting ps = mSettings.getPackageLPr(packageName);
- if (ps != null) {
- final int enabledState = ps.getEnabled(UserHandle.USER_SYSTEM);
- if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
- systemStubPackageNames.remove(i);
- continue;
- }
- }
- // install the package to replace the stub on /system
- try {
- installStubPackageLI(pkg, 0, scanFlags);
- ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
- UserHandle.USER_SYSTEM, "android");
- systemStubPackageNames.remove(i);
- } catch (PackageManagerException e) {
- Slog.e(TAG, "Failed to parse uncompressed system package: " + e.getMessage());
- }
- // any failed attempt to install the package will be cleaned up later
- }
- // disable any stub still left; these failed to install the full application
- for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
- final String pkgName = systemStubPackageNames.get(i);
- final PackageSetting ps = mSettings.getPackageLPr(pkgName);
- ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
- UserHandle.USER_SYSTEM, "android");
- logCriticalInfo(Log.ERROR, "Stub disabled; pkg: " + pkgName);
- }
- }
- /**
- * Extract, install and enable a stub package.
- * <p>If the compressed file can not be extracted / installed for any reason, the stub
- * APK will be installed and the package will be disabled. To recover from this situation,
- * the user will need to go into system settings and re-enable the package.
- */
- private boolean enableCompressedPackage(AndroidPackage stubPkg,
- @NonNull PackageSetting stubPkgSetting) {
- final int parseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY
- | ParsingPackageUtils.PARSE_ENFORCE_CODE;
- synchronized (mInstallLock) {
- final AndroidPackage pkg;
- try (PackageFreezer freezer =
- freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
- pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
- synchronized (mLock) {
- prepareAppDataAfterInstallLIF(pkg);
- try {
- updateSharedLibrariesLocked(pkg, stubPkgSetting, null, null,
- Collections.unmodifiableMap(mPackages));
- } catch (PackageManagerException e) {
- Slog.w(TAG, "updateAllSharedLibrariesLPw failed: ", e);
- }
- mPermissionManager.onPackageInstalled(pkg,
- PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
- UserHandle.USER_ALL);
- writeSettingsLPrTEMP();
- }
- } catch (PackageManagerException e) {
- // Whoops! Something went very wrong; roll back to the stub and disable the package
- try (PackageFreezer freezer =
- freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
- synchronized (mLock) {
- // NOTE: Ensure the system package is enabled; even for a compressed stub.
- // If we don't, installing the system package fails during scan
- enableSystemPackageLPw(stubPkg);
- }
- installPackageFromSystemLIF(stubPkg.getPath(),
- mUserManager.getUserIds() /*allUserHandles*/, null /*origUserHandles*/,
- true /*writeSettings*/);
- } catch (PackageManagerException pme) {
- // Serious WTF; we have to be able to install the stub
- Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
- pme);
- } finally {
- // Disable the package; the stub by itself is not runnable
- synchronized (mLock) {
- final PackageSetting stubPs = mSettings.getPackageLPr(
- stubPkg.getPackageName());
- if (stubPs != null) {
- stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
- UserHandle.USER_SYSTEM, "android");
- }
- writeSettingsLPrTEMP();
- }
- }
- return false;
- }
- clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
- | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- mDexManager.notifyPackageUpdated(pkg.getPackageName(),
- pkg.getBaseApkPath(), pkg.getSplitCodePaths());
- }
- return true;
- }
-
- private AndroidPackage installStubPackageLI(AndroidPackage stubPkg,
- @ParseFlags int parseFlags, @ScanFlags int scanFlags)
- throws PackageManagerException {
- if (DEBUG_COMPRESSION) {
- Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.getPackageName());
- }
- // uncompress the binary to its eventual destination on /data
- final File scanFile = decompressPackage(stubPkg.getPackageName(), stubPkg.getPath());
- if (scanFile == null) {
- throw new PackageManagerException(
- "Unable to decompress stub at " + stubPkg.getPath());
- }
- synchronized (mLock) {
- mSettings.disableSystemPackageLPw(stubPkg.getPackageName(), true /*replaced*/);
- }
- removePackageLI(stubPkg, true /*chatty*/);
- try {
- return scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
- } catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
- e);
- // Remove the failed install
- removeCodePathLI(scanFile);
- throw e;
- }
- }
-
- /**
- * Decompresses the given package on the system image onto
- * the /data partition.
- * @return The directory the package was decompressed into. Otherwise, {@code null}.
- */
- private File decompressPackage(String packageName, String codePath) {
- final File[] compressedFiles = getCompressedFiles(codePath);
- if (compressedFiles == null || compressedFiles.length == 0) {
- if (DEBUG_COMPRESSION) {
- Slog.i(TAG, "No files to decompress: " + codePath);
- }
- return null;
- }
- final File dstCodePath =
- getNextCodePath(Environment.getDataAppDirectory(null), packageName);
- int ret = PackageManager.INSTALL_SUCCEEDED;
- try {
- makeDirRecursive(dstCodePath, 0755);
- for (File srcFile : compressedFiles) {
- final String srcFileName = srcFile.getName();
- final String dstFileName = srcFileName.substring(
- 0, srcFileName.length() - COMPRESSED_EXTENSION.length());
- final File dstFile = new File(dstCodePath, dstFileName);
- ret = decompressFile(srcFile, dstFile);
- if (ret != PackageManager.INSTALL_SUCCEEDED) {
- logCriticalInfo(Log.ERROR, "Failed to decompress"
- + "; pkg: " + packageName
- + ", file: " + dstFileName);
- break;
- }
- }
- } catch (ErrnoException e) {
- logCriticalInfo(Log.ERROR, "Failed to decompress"
- + "; pkg: " + packageName
- + ", err: " + e.errno);
- }
- if (ret == PackageManager.INSTALL_SUCCEEDED) {
- final File libraryRoot = new File(dstCodePath, LIB_DIR_NAME);
- NativeLibraryHelper.Handle handle = null;
- try {
- handle = NativeLibraryHelper.Handle.create(dstCodePath);
- ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
- null /*abiOverride*/, false /*isIncremental*/);
- } catch (IOException e) {
- logCriticalInfo(Log.ERROR, "Failed to extract native libraries"
- + "; pkg: " + packageName);
- ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- } finally {
- IoUtils.closeQuietly(handle);
- }
- }
- if (ret == PackageManager.INSTALL_SUCCEEDED) {
- // NOTE: During boot, we have to delay releasing cblocks for no other reason than
- // we cannot retrieve the setting {@link Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL}.
- // When we no longer need to read that setting, cblock release can occur always
- // occur here directly
- if (!mSystemReady) {
- if (mReleaseOnSystemReady == null) {
- mReleaseOnSystemReady = new ArrayList<>();
- }
- mReleaseOnSystemReady.add(dstCodePath);
- } else {
- final ContentResolver resolver = mContext.getContentResolver();
- F2fsUtils.releaseCompressedBlocks(resolver, dstCodePath);
- }
- }
- if (ret != PackageManager.INSTALL_SUCCEEDED) {
- if (!dstCodePath.exists()) {
- return null;
- }
- removeCodePathLI(dstCodePath);
- return null;
- }
-
- return dstCodePath;
- }
@GuardedBy("mLock")
void updateInstantAppInstallerLocked(String modifiedPackage) {
@@ -9017,7 +8147,7 @@ public class PackageManagerService extends IPackageManager.Stub
/**
* Update given intent when being used to request {@link ResolveInfo}.
*/
- private Intent updateIntentForResolve(Intent intent) {
+ private static Intent updateIntentForResolve(Intent intent) {
if (intent.getSelector() != null) {
intent = intent.getSelector();
}
@@ -9822,7 +8952,7 @@ public class PackageManagerService extends IPackageManager.Stub
return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(pkg));
}
- private static boolean isCompatSignatureUpdateNeeded(VersionInfo ver) {
+ static boolean isCompatSignatureUpdateNeeded(VersionInfo ver) {
return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY;
}
@@ -9830,7 +8960,7 @@ public class PackageManagerService extends IPackageManager.Stub
return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(pkg));
}
- private static boolean isRecoverSignatureUpdateNeeded(VersionInfo ver) {
+ static boolean isRecoverSignatureUpdateNeeded(VersionInfo ver) {
return ver.databaseVersion < DatabaseVersion.SIGNATURE_MALFORMED_RECOVER;
}
@@ -10370,69 +9500,38 @@ public class PackageManagerService extends IPackageManager.Stub
}
@GuardedBy("mLock")
- private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType,
+ private ResolveInfo findPersistentPreferredActivityLP(Intent intent,
+ String resolvedType,
int flags, List<ResolveInfo> query, boolean debug, int userId) {
- final int N = query.size();
- PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId);
- // Get the list of persistent preferred activities that handle the intent
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for presistent preferred activities...");
- List<PersistentPreferredActivity> pprefs = ppir != null
- ? ppir.queryIntent(intent, resolvedType,
- (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
- userId)
- : null;
- if (pprefs != null && pprefs.size() > 0) {
- final int M = pprefs.size();
- for (int i=0; i<M; i++) {
- final PersistentPreferredActivity ppa = pprefs.get(i);
- if (DEBUG_PREFERRED || debug) {
- Slog.v(TAG, "Checking PersistentPreferredActivity ds="
- + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "<none>")
- + "\n component=" + ppa.mComponent);
- ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
- }
- final ActivityInfo ai = getActivityInfo(ppa.mComponent,
- flags | MATCH_DISABLED_COMPONENTS, userId);
- if (DEBUG_PREFERRED || debug) {
- Slog.v(TAG, "Found persistent preferred activity:");
- if (ai != null) {
- ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
- } else {
- Slog.v(TAG, " null");
- }
- }
- if (ai == null) {
- // This previously registered persistent preferred activity
- // component is no longer known. Ignore it and do NOT remove it.
- continue;
- }
- for (int j=0; j<N; j++) {
- final ResolveInfo ri = query.get(j);
- if (!ri.activityInfo.applicationInfo.packageName
- .equals(ai.applicationInfo.packageName)) {
- continue;
- }
- if (!ri.activityInfo.name.equals(ai.name)) {
- continue;
- }
- // Found a persistent preference that can handle the intent.
- if (DEBUG_PREFERRED || debug) {
- Slog.v(TAG, "Returning persistent preferred activity: " +
- ri.activityInfo.packageName + "/" + ri.activityInfo.name);
- }
- return ri;
- }
- }
- }
- return null;
+ return mComputer.findPersistentPreferredActivityLP(intent,
+ resolvedType,
+ flags, query, debug, userId);
}
- private boolean isHomeIntent(Intent intent) {
+ private static boolean isHomeIntent(Intent intent) {
return ACTION_MAIN.equals(intent.getAction())
&& intent.hasCategory(CATEGORY_HOME)
&& intent.hasCategory(CATEGORY_DEFAULT);
}
+
+ // findPreferredActivityBody returns two items: a "things changed" flag and a
+ // ResolveInfo, which is the preferred activity itself.
+ private static class FindPreferredActivityBodyResult {
+ boolean mChanged;
+ ResolveInfo mPreferredResolveInfo;
+ }
+
+ private FindPreferredActivityBodyResult findPreferredActivityInternal(
+ Intent intent, String resolvedType, int flags,
+ List<ResolveInfo> query, boolean always,
+ boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
+ return mComputer.findPreferredActivityInternal(
+ intent, resolvedType, flags,
+ query, always,
+ removeMatches, debug, userId, queryMayBeFiltered);
+ }
+
ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
List<ResolveInfo> query, boolean always,
boolean removeMatches, boolean debug, int userId) {
@@ -10451,206 +9550,22 @@ public class PackageManagerService extends IPackageManager.Stub
+ " is holding mLock", new Throwable());
}
if (!mUserManager.exists(userId)) return null;
- final int callingUid = Binder.getCallingUid();
- // Do NOT hold the packages lock; this calls up into the settings provider which
- // could cause a deadlock.
- final boolean isDeviceProvisioned =
- android.provider.Settings.Global.getInt(mContext.getContentResolver(),
- android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1;
- flags = updateFlagsForResolve(
- flags, userId, callingUid, false /*includeInstantApps*/,
- isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
- flags));
- intent = updateIntentForResolve(intent);
- // writer
- synchronized (mLock) {
- // Try to find a matching persistent preferred activity.
- ResolveInfo pri = findPersistentPreferredActivityLP(intent, resolvedType, flags, query,
- debug, userId);
- // If a persistent preferred activity matched, use it.
- if (pri != null) {
- return pri;
+ FindPreferredActivityBodyResult body = findPreferredActivityInternal(
+ intent, resolvedType, flags, query, always,
+ removeMatches, debug, userId, queryMayBeFiltered);
+ if (body.mChanged) {
+ if (DEBUG_PREFERRED) {
+ Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions");
}
-
- PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
- // Get the list of preferred activities that handle the intent
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
- List<PreferredActivity> prefs = pir != null
- ? pir.queryIntent(intent, resolvedType,
- (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
- userId)
- : null;
- if (prefs != null && prefs.size() > 0) {
- boolean changed = false;
- try {
- // First figure out how good the original match set is.
- // We will only allow preferred activities that came
- // from the same match quality.
- int match = 0;
-
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match...");
-
- final int N = query.size();
- for (int j=0; j<N; j++) {
- final ResolveInfo ri = query.get(j);
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Match for " + ri.activityInfo
- + ": 0x" + Integer.toHexString(match));
- if (ri.match > match) {
- match = ri.match;
- }
- }
-
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Best match: 0x"
- + Integer.toHexString(match));
-
- match &= IntentFilter.MATCH_CATEGORY_MASK;
- final int M = prefs.size();
- for (int i=0; i<M; i++) {
- final PreferredActivity pa = prefs.get(i);
- if (DEBUG_PREFERRED || debug) {
- Slog.v(TAG, "Checking PreferredActivity ds="
- + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>")
- + "\n component=" + pa.mPref.mComponent);
- pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
- }
- if (pa.mPref.mMatch != match) {
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping bad match "
- + Integer.toHexString(pa.mPref.mMatch));
- continue;
- }
- // If it's not an "always" type preferred activity and that's what we're
- // looking for, skip it.
- if (always && !pa.mPref.mAlways) {
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry");
- continue;
- }
- final ActivityInfo ai = getActivityInfo(
- pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS
- | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
- userId);
- if (DEBUG_PREFERRED || debug) {
- Slog.v(TAG, "Found preferred activity:");
- if (ai != null) {
- ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
- } else {
- Slog.v(TAG, " null");
- }
- }
- final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent)
- && !isDeviceProvisioned;
- final boolean allowSetMutation = !excludeSetupWizardHomeActivity
- && !queryMayBeFiltered;
- if (ai == null) {
- // Do not remove launcher's preferred activity during SetupWizard
- // due to it may not install yet
- if (!allowSetMutation) {
- continue;
- }
-
- // This previously registered preferred activity
- // component is no longer known. Most likely an update
- // to the app was installed and in the new version this
- // component no longer exists. Clean it up by removing
- // it from the preferred activities list, and skip it.
- Slog.w(TAG, "Removing dangling preferred activity: "
- + pa.mPref.mComponent);
- pir.removeFilter(pa);
- changed = true;
- continue;
- }
- for (int j=0; j<N; j++) {
- final ResolveInfo ri = query.get(j);
- if (!ri.activityInfo.applicationInfo.packageName
- .equals(ai.applicationInfo.packageName)) {
- continue;
- }
- if (!ri.activityInfo.name.equals(ai.name)) {
- continue;
- }
-
- if (removeMatches && allowSetMutation) {
- pir.removeFilter(pa);
- changed = true;
- if (DEBUG_PREFERRED) {
- Slog.v(TAG, "Removing match " + pa.mPref.mComponent);
- }
- break;
- }
-
- // Okay we found a previously set preferred or last chosen app.
- // If the result set is different from when this
- // was created, and is not a subset of the preferred set, we need to
- // clear it and re-ask the user their preference, if we're looking for
- // an "always" type entry.
-
- if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) {
- if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) {
- if (allowSetMutation) {
- // some components of the set are no longer present in
- // the query, but the preferred activity can still be reused
- if (DEBUG_PREFERRED) {
- Slog.i(TAG, "Result set changed, but PreferredActivity"
- + " is still valid as only non-preferred"
- + " components were removed for " + intent
- + " type " + resolvedType);
- }
- // remove obsolete components and re-add the up-to-date
- // filter
- PreferredActivity freshPa = new PreferredActivity(pa,
- pa.mPref.mMatch,
- pa.mPref.discardObsoleteComponents(query),
- pa.mPref.mComponent,
- pa.mPref.mAlways);
- pir.removeFilter(pa);
- pir.addFilter(freshPa);
- changed = true;
- } else {
- if (DEBUG_PREFERRED) {
- Slog.i(TAG, "Do not remove preferred activity");
- }
- }
- } else {
- if (allowSetMutation) {
- Slog.i(TAG,
- "Result set changed, dropping preferred activity "
- + "for " + intent + " type "
- + resolvedType);
- if (DEBUG_PREFERRED) {
- Slog.v(TAG,
- "Removing preferred activity since set changed "
- + pa.mPref.mComponent);
- }
- pir.removeFilter(pa);
- // Re-add the filter as a "last chosen" entry (!always)
- PreferredActivity lastChosen = new PreferredActivity(
- pa, pa.mPref.mMatch, null, pa.mPref.mComponent,
- false);
- pir.addFilter(lastChosen);
- changed = true;
- }
- return null;
- }
- }
-
- // Yay! Either the set matched or we're looking for the last chosen
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Returning preferred activity: "
- + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
- return ri;
- }
- }
- } finally {
- if (changed) {
- if (DEBUG_PREFERRED) {
- Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions");
- }
- scheduleWritePackageRestrictionsLocked(userId);
- }
- }
+ synchronized (mLock) {
+ scheduleWritePackageRestrictionsLocked(userId);
}
}
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "No preferred activity to return");
- return null;
+ if ((DEBUG_PREFERRED || debug) && body.mPreferredResolveInfo == null) {
+ Slog.v(TAG, "No preferred activity to return");
+ }
+ return body.mPreferredResolveInfo;
}
/*
@@ -11795,169 +10710,20 @@ public class PackageManagerService extends IPackageManager.Stub
return finalList;
}
- private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
- long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
- try {
- scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
-
- private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
- PackageParser2 packageParser, ExecutorService executorService) {
- final File[] files = scanDir.listFiles();
- if (ArrayUtils.isEmpty(files)) {
- Log.d(TAG, "No files in app dir " + scanDir);
- return;
- }
-
- if (DEBUG_PACKAGE_SCANNING) {
- Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
- + " flags=0x" + Integer.toHexString(parseFlags));
- }
-
- ParallelPackageParser parallelPackageParser =
- new ParallelPackageParser(packageParser, executorService);
-
- // Submit files for parsing in parallel
- int fileCount = 0;
- for (File file : files) {
- final boolean isPackage = (isApkFile(file) || file.isDirectory())
- && !PackageInstallerService.isStageName(file.getName());
- if (!isPackage) {
- // Ignore entries which are not packages
- continue;
- }
- parallelPackageParser.submit(file, parseFlags);
- fileCount++;
- }
-
- // Process results one by one
- for (; fileCount > 0; fileCount--) {
- ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
- Throwable throwable = parseResult.throwable;
- int errorCode = PackageManager.INSTALL_SUCCEEDED;
- String errorMsg = null;
-
- if (throwable == null) {
- // TODO(toddke): move lower in the scan chain
- // Static shared libraries have synthetic package names
- if (parseResult.parsedPackage.isStaticSharedLibrary()) {
- renameStaticSharedLibraryPackage(parseResult.parsedPackage);
- }
- try {
- addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
- currentTime, null);
- } catch (PackageManagerException e) {
- errorCode = e.error;
- errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage();
- Slog.w(TAG, errorMsg);
- }
- } else if (throwable instanceof PackageManagerException) {
- PackageManagerException e = (PackageManagerException) throwable;
- errorCode = e.error;
- errorMsg = "Failed to parse " + parseResult.scanFile + ": " + e.getMessage();
- Slog.w(TAG, errorMsg);
- } else {
- throw new IllegalStateException("Unexpected exception occurred while parsing "
- + parseResult.scanFile, throwable);
- }
-
- if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) {
- mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath(), errorMsg);
- }
-
- // Delete invalid userdata apps
- if ((scanFlags & SCAN_AS_SYSTEM) == 0
- && errorCode != PackageManager.INSTALL_SUCCEEDED) {
- logCriticalInfo(Log.WARN,
- "Deleting invalid package at " + parseResult.scanFile);
- removeCodePathLI(parseResult.scanFile);
- }
- }
- }
-
public static void reportSettingsProblem(int priority, String msg) {
logCriticalInfo(priority, msg);
}
- private void collectCertificatesLI(PackageSetting ps, ParsedPackage parsedPackage,
- boolean forceCollect, boolean skipVerify) throws PackageManagerException {
- // When upgrading from pre-N MR1, verify the package time stamp using the package
- // directory and not the APK file.
- final long lastModifiedTime = mIsPreNMR1Upgrade
- ? new File(parsedPackage.getPath()).lastModified()
- : getLastModifiedTime(parsedPackage);
- final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(parsedPackage);
- if (ps != null && !forceCollect
- && ps.getPathString().equals(parsedPackage.getPath())
- && ps.timeStamp == lastModifiedTime
- && !isCompatSignatureUpdateNeeded(settingsVersionForPackage)
- && !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) {
- if (ps.signatures.mSigningDetails.getSignatures() != null
- && ps.signatures.mSigningDetails.getSignatures().length != 0
- && ps.signatures.mSigningDetails.getSignatureSchemeVersion()
- != SignatureSchemeVersion.UNKNOWN) {
- // Optimization: reuse the existing cached signing data
- // if the package appears to be unchanged.
- parsedPackage.setSigningDetails(
- new SigningDetails(ps.signatures.mSigningDetails));
- return;
- }
-
- Slog.w(TAG, "PackageSetting for " + ps.name
- + " is missing signatures. Collecting certs again to recover them.");
- } else {
- Slog.i(TAG, parsedPackage.getPath() + " changed; collecting certs"
- + (forceCollect ? " (forced)" : ""));
- }
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
- final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
- final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails(
- input, parsedPackage, skipVerify);
- if (result.isError()) {
- throw new PackageManagerException(
- result.getErrorCode(), result.getErrorMessage(), result.getException());
- }
- parsedPackage.setSigningDetails(result.getResult());
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
- /**
- * Clear the package profile if this was an upgrade and the package
- * version was updated.
- */
- private void maybeClearProfilesForUpgradesLI(
- @Nullable PackageSetting originalPkgSetting,
- @NonNull AndroidPackage pkg) {
- if (originalPkgSetting == null || !isDeviceUpgrading()) {
- return;
- }
- if (originalPkgSetting.versionCode == pkg.getVersionCode()) {
- return;
- }
- clearAppProfilesLIF(pkg);
- if (DEBUG_INSTALL) {
- Slog.d(TAG, originalPkgSetting.name
- + " clear profile due to version change "
- + originalPkgSetting.versionCode + " != "
- + pkg.getVersionCode());
- }
- }
/**
* Traces a package scan.
* @see #scanPackageLI(File, int, int, long, UserHandle)
*/
@GuardedBy({"mInstallLock", "mLock"})
- private AndroidPackage scanPackageTracedLI(File scanFile, final int parseFlags,
+ AndroidPackage scanPackageTracedLI(File scanFile, final int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
try {
@@ -11989,318 +10755,9 @@ public class PackageManagerService extends IPackageManager.Stub
renameStaticSharedLibraryPackage(parsedPackage);
}
- return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
- }
-
- /**
- * Returns if forced apk verification can be skipped for the whole package, including splits.
- */
- private boolean canSkipForcedPackageVerification(AndroidPackage pkg) {
- if (!canSkipForcedApkVerification(pkg.getBaseApkPath())) {
- return false;
- }
- // TODO: Allow base and splits to be verified individually.
- String[] splitCodePaths = pkg.getSplitCodePaths();
- if (!ArrayUtils.isEmpty(splitCodePaths)) {
- for (int i = 0; i < splitCodePaths.length; i++) {
- if (!canSkipForcedApkVerification(splitCodePaths[i])) {
- return false;
- }
- }
- }
- return true;
- }
-
- /**
- * Returns if forced apk verification can be skipped, depending on current FSVerity setup and
- * whether the apk contains signed root hash. Note that the signer's certificate still needs to
- * match one in a trusted source, and should be done separately.
- */
- private boolean canSkipForcedApkVerification(String apkPath) {
- if (!PackageManagerServiceUtils.isLegacyApkVerityEnabled()) {
- return VerityUtils.hasFsverity(apkPath);
- }
-
- try {
- final byte[] rootHashObserved = VerityUtils.generateApkVerityRootHash(apkPath);
- if (rootHashObserved == null) {
- return false; // APK does not contain Merkle tree root hash.
- }
- synchronized (mInstallLock) {
- // Returns whether the observed root hash matches what kernel has.
- mInstaller.assertFsverityRootHashMatches(apkPath, rootHashObserved);
- return true;
- }
- } catch (InstallerException | IOException | DigestException |
- NoSuchAlgorithmException e) {
- Slog.w(TAG, "Error in fsverity check. Fallback to full apk verification.", e);
- }
- return false;
- }
-
- /**
- * Adds a new package to the internal data structures during platform initialization.
- * <p>After adding, the package is known to the system and available for querying.
- * <p>For packages located on the device ROM [eg. packages located in /system, /vendor,
- * etc...], additional checks are performed. Basic verification [such as ensuring
- * matching signatures, checking version codes, etc...] occurs if the package is
- * identical to a previously known package. If the package fails a signature check,
- * the version installed on /data will be removed. If the version of the new package
- * is less than or equal than the version on /data, it will be ignored.
- * <p>Regardless of the package location, the results are applied to the internal
- * structures and the package is made available to the rest of the system.
- * <p>NOTE: The return value should be removed. It's the passed in package object.
- */
- @GuardedBy({"mInstallLock", "mLock"})
- private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
- @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
- @Nullable UserHandle user)
- throws PackageManagerException {
- final boolean scanSystemPartition =
- (parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
- final String renamedPkgName;
- final PackageSetting disabledPkgSetting;
- final boolean isSystemPkgUpdated;
- final boolean pkgAlreadyExists;
- PackageSetting pkgSetting;
-
- synchronized (mLock) {
- renamedPkgName = mSettings.getRenamedPackageLPr(parsedPackage.getRealPackage());
- final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName);
- if (realPkgName != null) {
- ensurePackageRenamed(parsedPackage, renamedPkgName);
- }
- final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage,
- renamedPkgName);
- final PackageSetting installedPkgSetting = mSettings.getPackageLPr(
- parsedPackage.getPackageName());
- pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting;
- pkgAlreadyExists = pkgSetting != null;
- final String disabledPkgName = pkgAlreadyExists
- ? pkgSetting.name : parsedPackage.getPackageName();
- if (scanSystemPartition && !pkgAlreadyExists
- && mSettings.getDisabledSystemPkgLPr(disabledPkgName) != null) {
- // The updated-package data for /system apk remains inconsistently
- // after the package data for /data apk is lost accidentally.
- // To recover it, enable /system apk and install it as non-updated system app.
- Slog.w(TAG, "Inconsistent package setting of updated system app for "
- + disabledPkgName + ". To recover it, enable the system app"
- + "and install it as non-updated system app.");
- mSettings.removeDisabledSystemPackageLPw(disabledPkgName);
- }
- disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(disabledPkgName);
- isSystemPkgUpdated = disabledPkgSetting != null;
-
- if (DEBUG_INSTALL && isSystemPkgUpdated) {
- Slog.d(TAG, "updatedPkg = " + disabledPkgSetting);
- }
-
- final SharedUserSetting sharedUserSetting = (parsedPackage.getSharedUserId() != null)
- ? mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(),
- 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true)
- : null;
- if (DEBUG_PACKAGE_SCANNING
- && (parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0
- && sharedUserSetting != null) {
- Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId()
- + " (uid=" + sharedUserSetting.userId + "):"
- + " packages=" + sharedUserSetting.packages);
- }
-
- if (scanSystemPartition) {
- if (isSystemPkgUpdated) {
- // we're updating the disabled package, so, scan it as the package setting
- boolean isPlatformPackage = mPlatformPackage != null
- && Objects.equals(mPlatformPackage.getPackageName(),
- parsedPackage.getPackageName());
- final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
- null, disabledPkgSetting /* pkgSetting */,
- null /* disabledPkgSetting */, null /* originalPkgSetting */,
- null, parseFlags, scanFlags, isPlatformPackage, user, null);
- applyPolicy(parsedPackage, scanFlags, mPlatformPackage, true);
- final ScanResult scanResult =
- scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L);
- if (scanResult.mExistingSettingCopied
- && scanResult.mRequest.mPkgSetting != null) {
- scanResult.mRequest.mPkgSetting.updateFrom(scanResult.mPkgSetting);
- }
- }
- }
- }
-
- final boolean newPkgChangedPaths = pkgAlreadyExists
- && !pkgSetting.getPathString().equals(parsedPackage.getPath());
- final boolean newPkgVersionGreater =
- pkgAlreadyExists && parsedPackage.getLongVersionCode() > pkgSetting.versionCode;
- final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
- && newPkgChangedPaths && newPkgVersionGreater;
- if (isSystemPkgBetter) {
- // The version of the application on /system is greater than the version on
- // /data. Switch back to the application on /system.
- // It's safe to assume the application on /system will correctly scan. If not,
- // there won't be a working copy of the application.
- synchronized (mLock) {
- // just remove the loaded entries from package lists
- mPackages.remove(pkgSetting.name);
- }
-
- logCriticalInfo(Log.WARN,
- "System package updated;"
- + " name: " + pkgSetting.name
- + "; " + pkgSetting.versionCode + " --> " + parsedPackage.getLongVersionCode()
- + "; " + pkgSetting.getPathString()
- + " --> " + parsedPackage.getPath());
-
- final InstallArgs args = createInstallArgsForExisting(
- pkgSetting.getPathString(), getAppDexInstructionSets(
- pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
- args.cleanUpResourcesLI();
- synchronized (mLock) {
- mSettings.enableSystemPackageLPw(pkgSetting.name);
- }
- }
-
- // The version of the application on the /system partition is less than or
- // equal to the version on the /data partition. Throw an exception and use
- // the application already installed on the /data partition.
- if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) {
- // In the case of a skipped package, commitReconciledScanResultLocked is not called to
- // add the object to the "live" data structures, so this is the final mutation step
- // for the package. Which means it needs to be finalized here to cache derived fields.
- // This is relevant for cases where the disabled system package is used for flags or
- // other metadata.
- parsedPackage.hideAsFinal();
- throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName()
- + " at " + parsedPackage.getPath() + " ignored: updated version "
- + (pkgAlreadyExists ? String.valueOf(pkgSetting.versionCode) : "unknown")
- + " better than this " + parsedPackage.getLongVersionCode());
- }
-
- // Verify certificates against what was last scanned. Force re-collecting certificate in two
- // special cases:
- // 1) when scanning system, force re-collect only if system is upgrading.
- // 2) when scannning /data, force re-collect only if the app is privileged (updated from
- // preinstall, or treated as privileged, e.g. due to shared user ID).
- final boolean forceCollect = scanSystemPartition ? mIsUpgrade
- : PackageManagerServiceUtils.isApkVerificationForced(pkgSetting);
- if (DEBUG_VERIFY && forceCollect) {
- Slog.d(TAG, "Force collect certificate of " + parsedPackage.getPackageName());
- }
-
- // Full APK verification can be skipped during certificate collection, only if the file is
- // in verified partition, or can be verified on access (when apk verity is enabled). In both
- // cases, only data in Signing Block is verified instead of the whole file.
- // TODO(b/136132412): skip for Incremental installation
- final boolean skipVerify = scanSystemPartition
- || (forceCollect && canSkipForcedPackageVerification(parsedPackage));
- collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify);
-
- // Reset profile if the application version is changed
- maybeClearProfilesForUpgradesLI(pkgSetting, parsedPackage);
-
- /*
- * A new system app appeared, but we already had a non-system one of the
- * same name installed earlier.
- */
- boolean shouldHideSystemApp = false;
- // A new application appeared on /system, but, we already have a copy of
- // the application installed on /data.
- if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists
- && !pkgSetting.isSystem()) {
-
- if (!parsedPackage.getSigningDetails()
- .checkCapability(pkgSetting.signatures.mSigningDetails,
- SigningDetails.CertCapabilities.INSTALLED_DATA)
- && !pkgSetting.signatures.mSigningDetails.checkCapability(
- parsedPackage.getSigningDetails(),
- SigningDetails.CertCapabilities.ROLLBACK)) {
- logCriticalInfo(Log.WARN,
- "System package signature mismatch;"
- + " name: " + pkgSetting.name);
- try (@SuppressWarnings("unused") PackageFreezer freezer = freezePackage(
- parsedPackage.getPackageName(),
- "scanPackageInternalLI")) {
- deletePackageLIF(parsedPackage.getPackageName(), null, true,
- mUserManager.getUserIds(), 0, null, false);
- }
- pkgSetting = null;
- } else if (newPkgVersionGreater) {
- // The application on /system is newer than the application on /data.
- // Simply remove the application on /data [keeping application data]
- // and replace it with the version on /system.
- logCriticalInfo(Log.WARN,
- "System package enabled;"
- + " name: " + pkgSetting.name
- + "; " + pkgSetting.versionCode + " --> "
- + parsedPackage.getLongVersionCode()
- + "; " + pkgSetting.getPathString() + " --> "
- + parsedPackage.getPath());
- InstallArgs args = createInstallArgsForExisting(
- pkgSetting.getPathString(), getAppDexInstructionSets(
- pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
- synchronized (mInstallLock) {
- args.cleanUpResourcesLI();
- }
- } else {
- // The application on /system is older than the application on /data. Hide
- // the application on /system and the version on /data will be scanned later
- // and re-added like an update.
- shouldHideSystemApp = true;
- logCriticalInfo(Log.INFO,
- "System package disabled;"
- + " name: " + pkgSetting.name
- + "; old: " + pkgSetting.getPathString() + " @ "
- + pkgSetting.versionCode
- + "; new: " + parsedPackage.getPath() + " @ "
- + parsedPackage.getPath());
- }
- }
-
- final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags
- | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
- if (scanResult.mSuccess) {
- synchronized (mLock) {
- boolean appIdCreated = false;
- try {
- final String pkgName = scanResult.mPkgSetting.name;
- final Map<String, ReconciledPackage> reconcileResult = reconcilePackagesLocked(
- new ReconcileRequest(
- Collections.singletonMap(pkgName, scanResult),
- mSharedLibraries,
- mPackages,
- Collections.singletonMap(
- pkgName, getSettingsVersionForPackage(parsedPackage)),
- Collections.singletonMap(pkgName,
- getSharedLibLatestVersionSetting(scanResult))),
- mSettings.getKeySetManagerService(), mInjector);
- appIdCreated = optimisticallyRegisterAppId(scanResult);
- commitReconciledScanResultLocked(
- reconcileResult.get(pkgName), mUserManager.getUserIds());
- } catch (PackageManagerException e) {
- if (appIdCreated) {
- cleanUpAppIdCreation(scanResult);
- }
- throw e;
- }
- }
- }
-
- if (shouldHideSystemApp) {
- synchronized (mLock) {
- mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true);
- }
- }
- if (mIncrementalManager != null && isIncrementalPath(parsedPackage.getPath())) {
- if (pkgSetting != null && pkgSetting.isPackageLoading()) {
- // Continue monitoring loading progress of active incremental packages
- final IncrementalStatesCallback incrementalStatesCallback =
- new IncrementalStatesCallback(parsedPackage.getPackageName(), this);
- pkgSetting.setIncrementalStatesCallback(incrementalStatesCallback);
- mIncrementalManager.registerLoadingProgressCallback(parsedPackage.getPath(),
- new IncrementalProgressListener(parsedPackage.getPackageName(), this));
- }
- }
- return scanResult.mPkgSetting.pkg;
+ final InitAndSystemPackageHelper helper = new InitAndSystemPackageHelper(this);
+ return helper.addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user,
+ mPlatformPackage, mIsUpgrade, mIsPreNMR1Upgrade);
}
// TODO:(b/135203078): Move to parsing
@@ -13264,7 +11721,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private void clearAppProfilesLIF(AndroidPackage pkg) {
+ void clearAppProfilesLIF(AndroidPackage pkg) {
if (pkg == null) {
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
@@ -13333,7 +11790,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
@GuardedBy("mLock")
- private void updateSharedLibrariesLocked(AndroidPackage pkg, PackageSetting pkgSetting,
+ void updateSharedLibrariesLocked(AndroidPackage pkg, PackageSetting pkgSetting,
@Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting,
Map<String, AndroidPackage> availablePackages)
throws PackageManagerException {
@@ -13743,7 +12200,7 @@ public class PackageManagerService extends IPackageManager.Stub
// method. Also, we need to solve the problem of potentially creating a new shared user
// setting. That can probably be done later and patch things up after the fact.
@GuardedBy({"mInstallLock", "mLock"})
- private ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage,
+ ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage,
final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user, String cpuAbiOverride) throws PackageManagerException {
@@ -13956,7 +12413,7 @@ public class PackageManagerService extends IPackageManager.Stub
* <p>This may differ from the package's actual name if the application has already
* been installed under one of this package's original names.
*/
- private static @Nullable String getRealPackageName(@NonNull AndroidPackage pkg,
+ static @Nullable String getRealPackageName(@NonNull AndroidPackage pkg,
@Nullable String renamedPkgName) {
if (isPackageRenamed(pkg, renamedPkgName)) {
return pkg.getRealPackage();
@@ -13978,7 +12435,7 @@ public class PackageManagerService extends IPackageManager.Stub
* shared user [if any].
*/
@GuardedBy("mLock")
- private @Nullable PackageSetting getOriginalPackageLocked(@NonNull AndroidPackage pkg,
+ @Nullable PackageSetting getOriginalPackageLocked(@NonNull AndroidPackage pkg,
@Nullable String renamedPkgName) {
if (isPackageRenamed(pkg, renamedPkgName)) {
return null;
@@ -14017,7 +12474,7 @@ public class PackageManagerService extends IPackageManager.Stub
* <p>When we've already installed the package under an original name, update
* the new package so we can continue to have the old name.
*/
- private static void ensurePackageRenamed(@NonNull ParsedPackage parsedPackage,
+ static void ensurePackageRenamed(@NonNull ParsedPackage parsedPackage,
@NonNull String renamedPackageName) {
if (!parsedPackage.getOriginalPackages().contains(renamedPackageName)
|| parsedPackage.getPackageName().equals(renamedPackageName)) {
@@ -14130,7 +12587,7 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mInstallLock")
@VisibleForTesting
@NonNull
- static ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
+ ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
Injector injector,
boolean isUnderFactoryTest, long currentTime)
throws PackageManagerException {
@@ -14533,7 +12990,7 @@ public class PackageManagerService extends IPackageManager.Stub
* Implementation detail: This method must NOT have any side effect. It would
* ideally be static, but, it requires locks to read system state.
*/
- private static void applyPolicy(ParsedPackage parsedPackage,
+ static void applyPolicy(ParsedPackage parsedPackage,
final @ScanFlags int scanFlags, AndroidPackage platformPkg,
boolean isUpdatedSystemApp) {
if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
@@ -15819,8 +14276,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
- void sendPackagesSuspendedForUser(String[] pkgList, int[] uidList, int userId,
- boolean suspended) {
+ void sendPackagesSuspendedForUser(String intent, String[] pkgList, int[] uidList, int userId) {
final List<List<String>> pkgsToSend = new ArrayList(pkgList.length);
final List<IntArray> uidsToSend = new ArrayList(pkgList.length);
final List<SparseArray<int[]>> allowListsToSend = new ArrayList(pkgList.length);
@@ -15861,11 +14317,8 @@ public class PackageManagerService extends IPackageManager.Stub
extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidsToSend.get(i).toArray());
final SparseArray<int[]> allowList = allowListsToSend.get(i).size() == 0
? null : allowListsToSend.get(i);
- sendPackageBroadcast(
- suspended ? Intent.ACTION_PACKAGES_SUSPENDED
- : Intent.ACTION_PACKAGES_UNSUSPENDED,
- null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null,
- userIds, null, allowList, null);
+ sendPackageBroadcast(intent, null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null,
+ null, userIds, null, allowList, null);
}
}
@@ -16179,6 +14632,8 @@ public class PackageManagerService extends IPackageManager.Stub
final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
final IntArray changedUids = new IntArray(packageNames.length);
+ final List<String> modifiedPackagesList = new ArrayList<>(packageNames.length);
+ final IntArray modifiedUids = new IntArray(packageNames.length);
final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
final boolean[] canSuspend = suspended ? canSuspendPackageForUserInternal(packageNames,
userId) : null;
@@ -16206,13 +14661,14 @@ public class PackageManagerService extends IPackageManager.Stub
unactionedPackages.add(packageName);
continue;
}
- boolean packageUnsuspended;
+ final boolean packageUnsuspended;
+ final boolean packageModified;
synchronized (mLock) {
if (suspended) {
- pkgSetting.addOrUpdateSuspension(callingPackage, dialogInfo, appExtras,
- launcherExtras, userId);
+ packageModified = pkgSetting.addOrUpdateSuspension(callingPackage,
+ dialogInfo, appExtras, launcherExtras, userId);
} else {
- pkgSetting.removeSuspension(callingPackage, userId);
+ packageModified = pkgSetting.removeSuspension(callingPackage, userId);
}
packageUnsuspended = !suspended && !pkgSetting.getSuspended(userId);
}
@@ -16220,18 +14676,29 @@ public class PackageManagerService extends IPackageManager.Stub
changedPackagesList.add(packageName);
changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
}
+ if (packageModified) {
+ modifiedPackagesList.add(packageName);
+ modifiedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
+ }
}
if (!changedPackagesList.isEmpty()) {
- final String[] changedPackages = changedPackagesList.toArray(
- new String[changedPackagesList.size()]);
- sendPackagesSuspendedForUser(changedPackages, changedUids.toArray(), userId, suspended);
+ final String[] changedPackages = changedPackagesList.toArray(new String[0]);
+ sendPackagesSuspendedForUser(
+ suspended ? Intent.ACTION_PACKAGES_SUSPENDED
+ : Intent.ACTION_PACKAGES_UNSUSPENDED,
+ changedPackages, changedUids.toArray(), userId);
sendMyPackageSuspendedOrUnsuspended(changedPackages, suspended, userId);
synchronized (mLock) {
scheduleWritePackageRestrictionsLocked(userId);
}
}
- return unactionedPackages.toArray(new String[unactionedPackages.size()]);
+ // Send the suspension changed broadcast to ensure suspension state is not stale.
+ if (!modifiedPackagesList.isEmpty()) {
+ sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
+ modifiedPackagesList.toArray(new String[0]), modifiedUids.toArray(), userId);
+ }
+ return unactionedPackages.toArray(new String[0]);
}
@Override
@@ -16360,7 +14827,8 @@ public class PackageManagerService extends IPackageManager.Stub
final String[] packageArray = unsuspendedPackages.toArray(
new String[unsuspendedPackages.size()]);
sendMyPackageSuspendedOrUnsuspended(packageArray, false, userId);
- sendPackagesSuspendedForUser(packageArray, unsuspendedUids.toArray(), userId, false);
+ sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_UNSUSPENDED,
+ packageArray, unsuspendedUids.toArray(), userId);
}
}
@@ -16639,30 +15107,6 @@ public class PackageManagerService extends IPackageManager.Stub
return Math.max(timeout, DEFAULT_VERIFICATION_TIMEOUT);
}
-
- /**
- * Get the default verification agent response code.
- *
- * @return default verification response code
- */
- private int getDefaultVerificationResponse(UserHandle user) {
- if (mUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) {
- return PackageManager.VERIFICATION_REJECT;
- }
- return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
- android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
- DEFAULT_VERIFICATION_RESPONSE);
- }
-
- /**
- * Get the default integrity verification response code.
- */
- private int getDefaultIntegrityVerificationResponse() {
- // We are not exposing this as a user-configurable setting because we don't want to provide
- // an easy way to get around the integrity check.
- return PackageManager.VERIFICATION_REJECT;
- }
-
@Deprecated
@Override
public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {
@@ -16733,17 +15177,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- /**
- * Get the "allow unknown sources" setting.
- *
- * @return the current "allow unknown sources" setting
- */
- private int getUnknownSourcesSettings() {
- return android.provider.Settings.Secure.getInt(mContext.getContentResolver(),
- android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS,
- -1);
- }
-
@Override
public void setInstallerPackageName(String targetPackage, String installerPackageName) {
final int callingUid = Binder.getCallingUid();
@@ -17060,7 +15493,7 @@ public class PackageManagerService extends IPackageManager.Stub
});
}
- private void sendFirstLaunchBroadcast(String pkgName, String installerPkg,
+ void sendFirstLaunchBroadcast(String pkgName, String installerPkg,
int[] userIds, int[] instantUserIds) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0,
installerPkg, null, userIds, instantUserIds, null /* broadcastAllowList */, null);
@@ -17099,19 +15532,8 @@ public class PackageManagerService extends IPackageManager.Stub
return new File(firstLevelDir, packageName + "-" + suffix);
}
- private void removeNativeBinariesLI(PackageSetting ps) {
- if (ps != null) {
- NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
- }
- }
-
@GuardedBy("mLock")
- private void enableSystemPackageLPw(AndroidPackage pkg) {
- mSettings.enableSystemPackageLPw(pkg.getPackageName());
- }
-
- @GuardedBy("mLock")
- static Map<String, ReconciledPackage> reconcilePackagesLocked(
+ Map<String, ReconciledPackage> reconcilePackagesLocked(
final ReconcileRequest request, KeySetManagerService ksms, Injector injector)
throws ReconcileFailure {
final Map<String, ScanResult> scannedPackages = request.mScannedPackages;
@@ -17987,7 +16409,10 @@ public class PackageManagerService extends IPackageManager.Stub
Slog.i(TAG, "Enabling system stub after removal; pkg: "
+ stubPkg.getPackageName());
}
- enableCompressedPackage(stubPkg, stubPs);
+ final InitAndSystemPackageHelper helper =
+ new InitAndSystemPackageHelper(this);
+ helper.enableCompressedPackage(stubPkg, stubPs, mDefParseFlags,
+ mDirsToScanAsSystem);
} else if (DEBUG_COMPRESSION) {
Slog.i(TAG, "System stub disabled for all users, leaving uncompressed "
+ "after removal; pkg: " + stubPkg.getPackageName());
@@ -18006,7 +16431,7 @@ public class PackageManagerService extends IPackageManager.Stub
* make sure this flag is set for partially installed apps. If not its meaningless to
* delete a partially installed application.
*/
- private void removePackageDataLIF(final PackageSetting deletedPs, @NonNull int[] allUserHandles,
+ void removePackageDataLIF(final PackageSetting deletedPs, @NonNull int[] allUserHandles,
PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
String packageName = deletedPs.name;
if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs);
@@ -18130,181 +16555,7 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
- /*
- * Tries to delete system package.
- */
- private void deleteSystemPackageLIF(DeletePackageAction action, PackageSetting deletedPs,
- @NonNull int[] allUserHandles, int flags, @Nullable PackageRemovedInfo outInfo,
- boolean writeSettings)
- throws SystemDeleteException {
- final boolean applyUserRestrictions = outInfo != null && (outInfo.mOrigUsers != null);
- final AndroidPackage deletedPkg = deletedPs.pkg;
- // Confirm if the system package has been updated
- // An updated system app can be deleted. This will also have to restore
- // the system pkg from system partition
- // reader
- final PackageSetting disabledPs = action.mDisabledPs;
- if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.getPackageName()
- + " disabledPs=" + disabledPs);
- Slog.d(TAG, "Deleting system pkg from data partition");
-
- if (DEBUG_REMOVE) {
- if (applyUserRestrictions) {
- Slog.d(TAG, "Remembering install states:");
- for (int userId : allUserHandles) {
- final boolean finstalled = ArrayUtils.contains(outInfo.mOrigUsers, userId);
- Slog.d(TAG, " u=" + userId + " inst=" + finstalled);
- }
- }
- }
-
- if (outInfo != null) {
- // Delete the updated package
- outInfo.mIsRemovedPackageSystemUpdate = true;
- }
-
- if (disabledPs.versionCode < deletedPs.versionCode) {
- // Delete data for downgrades
- flags &= ~PackageManager.DELETE_KEEP_DATA;
- } else {
- // Preserve data by setting flag
- flags |= PackageManager.DELETE_KEEP_DATA;
- }
-
- deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles,
- outInfo, writeSettings);
-
- // writer
- synchronized (mLock) {
- // NOTE: The system package always needs to be enabled; even if it's for
- // a compressed stub. If we don't, installing the system package fails
- // during scan [scanning checks the disabled packages]. We will reverse
- // this later, after we've "installed" the stub.
- // Reinstate the old system package
- enableSystemPackageLPw(disabledPs.pkg);
- // Remove any native libraries from the upgraded package.
- removeNativeBinariesLI(deletedPs);
- }
-
- // Install the system package
- if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
- try {
- installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles,
- outInfo == null ? null : outInfo.mOrigUsers, writeSettings);
- } catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": "
- + e.getMessage());
- // TODO(patb): can we avoid this; throw would come from scan...
- throw new SystemDeleteException(e);
- } finally {
- if (disabledPs.pkg.isStub()) {
- // We've re-installed the stub; make sure it's disabled here. If package was
- // originally enabled, we'll install the compressed version of the application
- // and re-enable it afterward.
- final PackageSetting stubPs = mSettings.getPackageLPr(deletedPkg.getPackageName());
- if (stubPs != null) {
- int userId = action.mUser == null
- ? UserHandle.USER_ALL : action.mUser.getIdentifier();
- if (userId == UserHandle.USER_ALL) {
- for (int aUserId : allUserHandles) {
- stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, aUserId, "android");
- }
- } else if (userId >= UserHandle.USER_SYSTEM) {
- stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, userId, "android");
- }
- }
- }
- }
- }
-
- /**
- * Installs a package that's already on the system partition.
- */
- private void installPackageFromSystemLIF(@NonNull String codePathString,
- @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings)
- throws PackageManagerException {
- final File codePath = new File(codePathString);
- @ParseFlags int parseFlags =
- mDefParseFlags
- | ParsingPackageUtils.PARSE_MUST_BE_APK
- | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
- @ScanFlags int scanFlags = SCAN_AS_SYSTEM;
- for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
- ScanPartition partition = mDirsToScanAsSystem.get(i);
- if (partition.containsFile(codePath)) {
- scanFlags |= partition.scanFlag;
- if (partition.containsPrivApp(codePath)) {
- scanFlags |= SCAN_AS_PRIVILEGED;
- }
- break;
- }
- }
-
- final AndroidPackage pkg =
- scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
-
- PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.getPackageName());
-
- try {
- // update shared libraries for the newly re-installed system package
- updateSharedLibrariesLocked(pkg, pkgSetting, null, null,
- Collections.unmodifiableMap(mPackages));
- } catch (PackageManagerException e) {
- Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
- }
-
- prepareAppDataAfterInstallLIF(pkg);
-
- // writer
- synchronized (mLock) {
- PackageSetting ps = mSettings.getPackageLPr(pkg.getPackageName());
-
- final boolean applyUserRestrictions = origUserHandles != null;
- if (applyUserRestrictions) {
- boolean installedStateChanged = false;
- if (DEBUG_REMOVE) {
- Slog.d(TAG, "Propagating install state across reinstall");
- }
- for (int userId : allUserHandles) {
- final boolean installed = ArrayUtils.contains(origUserHandles, userId);
- if (DEBUG_REMOVE) {
- Slog.d(TAG, " user " + userId + " => " + installed);
- }
- if (installed != ps.getInstalled(userId)) {
- installedStateChanged = true;
- }
- ps.setInstalled(installed, userId);
- if (installed) {
- ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId);
- }
- }
- // Regardless of writeSettings we need to ensure that this restriction
- // state propagation is persisted
- mSettings.writeAllUsersPackageRestrictionsLPr();
- if (installedStateChanged) {
- mSettings.writeKernelMappingLPr(ps);
- }
- }
-
- // The method below will take care of removing obsolete permissions and granting
- // install permissions.
- mPermissionManager.onPackageInstalled(pkg,
- PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
- UserHandle.USER_ALL);
- for (final int userId : allUserHandles) {
- if (applyUserRestrictions) {
- mSettings.writePermissionStateForUserLPr(userId, false);
- }
- }
-
- // can downgrade to reader here
- if (writeSettings) {
- writeSettingsLPrTEMP();
- }
- }
- }
-
- private void deleteInstalledPackageLIF(PackageSetting ps,
+ void deleteInstalledPackageLIF(PackageSetting ps,
boolean deleteCodeAndResources, int flags, @NonNull int[] allUserHandles,
PackageRemovedInfo outInfo, boolean writeSettings) {
synchronized (mLock) {
@@ -18409,7 +16660,7 @@ public class PackageManagerService extends IPackageManager.Stub
/*
* This method handles package deletion in general
*/
- private boolean deletePackageLIF(@NonNull String packageName, UserHandle user,
+ boolean deletePackageLIF(@NonNull String packageName, UserHandle user,
boolean deleteCodeAndResources, @NonNull int[] allUserHandles, int flags,
PackageRemovedInfo outInfo, boolean writeSettings) {
final DeletePackageAction action;
@@ -18504,7 +16755,9 @@ public class PackageManagerService extends IPackageManager.Stub
if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);
// When an updated system application is deleted we delete the existing resources
// as well and fall back to existing code in system partition
- deleteSystemPackageLIF(action, ps, allUserHandles, flags, outInfo, writeSettings);
+ final InitAndSystemPackageHelper helper = new InitAndSystemPackageHelper(this);
+ helper.deleteSystemPackageLIF(action, ps, allUserHandles, flags, outInfo,
+ writeSettings, mDefParseFlags, mDirsToScanAsSystem);
} else {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,
@@ -19112,7 +17365,7 @@ public class PackageManagerService extends IPackageManager.Stub
mSettings.clearPackagePreferredActivities(packageName, outUserChanged, userId);
}
- private void restorePermissionsAndUpdateRolesForNewUserInstall(String packageName,
+ void restorePermissionsAndUpdateRolesForNewUserInstall(String packageName,
@UserIdInt int userId) {
// We may also need to apply pending (restored) runtime permission grants
// within these users.
@@ -20190,7 +18443,9 @@ public class PackageManagerService extends IPackageManager.Stub
if (isSystemStub
&& (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) {
- if (!enableCompressedPackage(deletedPkg, pkgSetting)) {
+ final InitAndSystemPackageHelper helper = new InitAndSystemPackageHelper(this);
+ if (!helper.enableCompressedPackage(deletedPkg, pkgSetting, mDefParseFlags,
+ mDirsToScanAsSystem)) {
Slog.w(TAG, "Failed setApplicationEnabledSetting: failed to enable "
+ "commpressed package " + setting.getPackageName());
updateAllowed[i] = false;
@@ -20373,7 +18628,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private void sendPackageChangedBroadcast(String packageName,
+ void sendPackageChangedBroadcast(String packageName,
boolean dontKillApp, ArrayList<String> componentNames, int packageUid, String reason) {
if (DEBUG_INSTALL)
Log.v(TAG, "Sending package changed: package=" + packageName + " components="
@@ -21090,15 +19345,24 @@ public class PackageManagerService extends IPackageManager.Stub
final String packageName = dumpState.getTargetPackageName();
final boolean checkin = dumpState.isCheckIn();
+
+ // Return if the package doesn't exist.
+ if (packageName != null
+ && getPackageSetting(packageName) == null
+ && !mApexManager.isApexPackage(packageName)) {
+ pw.println("Unable to find package: " + packageName);
+ return;
+ }
+
if (checkin) {
pw.println("vers,1");
}
// reader
- if (dumpState.isDumping(DumpState.DUMP_VERSION) && packageName == null) {
- if (!checkin) {
- dump(DumpState.DUMP_VERSION, fd, pw, dumpState);
- }
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_VERSION)
+ && packageName == null) {
+ dump(DumpState.DUMP_VERSION, fd, pw, dumpState);
}
if (!checkin
@@ -21129,7 +19393,8 @@ public class PackageManagerService extends IPackageManager.Stub
ipw.decreaseIndent();
}
- if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) && packageName == null) {
+ if (dumpState.isDumping(DumpState.DUMP_VERIFIERS)
+ && packageName == null) {
final String requiredVerifierPackage = mRequiredVerifierPackage;
if (!checkin) {
if (dumpState.onTitlePrinted()) {
@@ -21150,14 +19415,16 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER) && packageName == null) {
+ if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER)
+ && packageName == null) {
final DomainVerificationProxy proxy = mDomainVerificationManager.getProxy();
final ComponentName verifierComponent = proxy.getComponentName();
if (verifierComponent != null) {
String verifierPackageName = verifierComponent.getPackageName();
if (!checkin) {
- if (dumpState.onTitlePrinted())
+ if (dumpState.onTitlePrinted()) {
pw.println();
+ }
pw.println("Domain Verifier:");
pw.print(" Using: ");
pw.print(verifierPackageName);
@@ -21177,11 +19444,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) {
+ if (dumpState.isDumping(DumpState.DUMP_LIBS)
+ && packageName == null) {
dump(DumpState.DUMP_LIBS, fd, pw, dumpState);
}
- if (dumpState.isDumping(DumpState.DUMP_FEATURES) && packageName == null) {
+ if (dumpState.isDumping(DumpState.DUMP_FEATURES)
+ && packageName == null) {
if (dumpState.onTitlePrinted()) {
pw.println();
}
@@ -21191,12 +19460,7 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mAvailableFeatures) {
for (FeatureInfo feat : mAvailableFeatures.values()) {
- if (checkin) {
- pw.print("feat,");
- pw.print(feat.name);
- pw.print(",");
- pw.println(feat.version);
- } else {
+ if (!checkin) {
pw.print(" ");
pw.print(feat.name);
if (feat.version > 0) {
@@ -21204,55 +19468,73 @@ public class PackageManagerService extends IPackageManager.Stub
pw.print(feat.version);
}
pw.println();
+ } else {
+ pw.print("feat,");
+ pw.print(feat.name);
+ pw.print(",");
+ pw.println(feat.version);
}
}
}
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) {
synchronized (mLock) {
mComponentResolver.dumpActivityResolvers(pw, dumpState, packageName);
}
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) {
synchronized (mLock) {
mComponentResolver.dumpReceiverResolvers(pw, dumpState, packageName);
}
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) {
synchronized (mLock) {
mComponentResolver.dumpServiceResolvers(pw, dumpState, packageName);
}
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) {
synchronized (mLock) {
mComponentResolver.dumpProviderResolvers(pw, dumpState, packageName);
}
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
dump(DumpState.DUMP_PREFERRED, fd, pw, dumpState);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)
+ && packageName == null) {
dump(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
dump(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
- mSettings.dumpPermissions(pw, packageName, permissionNames, dumpState);
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
+ synchronized (mLock) {
+ mSettings.dumpPermissions(pw, packageName, permissionNames, dumpState);
+ }
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
synchronized (mLock) {
mComponentResolver.dumpContentProviders(pw, dumpState, packageName);
}
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
synchronized (mLock) {
mSettings.getKeySetManagerService().dumpLPr(pw, packageName, dumpState);
}
@@ -21267,7 +19549,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (dumpState.isDumping(DumpState.DUMP_QUERIES)) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_QUERIES)) {
dump(DumpState.DUMP_QUERIES, fd, pw, dumpState);
}
@@ -21279,8 +19562,12 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (dumpState.isDumping(DumpState.DUMP_CHANGES)) {
- if (dumpState.onTitlePrinted()) pw.println();
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_CHANGES)
+ && packageName == null) {
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
pw.println("Package Changes:");
synchronized (mLock) {
pw.print(" Sequence number="); pw.println(mChangedPackagesSequenceNumber);
@@ -21306,11 +19593,14 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_FROZEN) && packageName == null) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_FROZEN)
+ && packageName == null) {
// XXX should handle packageName != null by dumping only install data that
// the given package is involved with.
- if (dumpState.onTitlePrinted()) pw.println();
-
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
ipw.println();
ipw.println("Frozen packages:");
@@ -21327,9 +19617,12 @@ public class PackageManagerService extends IPackageManager.Stub
ipw.decreaseIndent();
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_VOLUMES) && packageName == null) {
- if (dumpState.onTitlePrinted()) pw.println();
-
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_VOLUMES)
+ && packageName == null) {
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
ipw.println();
ipw.println("Loaded volumes:");
@@ -21346,52 +19639,65 @@ public class PackageManagerService extends IPackageManager.Stub
ipw.decreaseIndent();
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
&& packageName == null) {
synchronized (mLock) {
mComponentResolver.dumpServicePermissions(pw, dumpState);
}
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) {
- if (dumpState.onTitlePrinted()) pw.println();
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_DEXOPT)) {
dump(DumpState.DUMP_DEXOPT, fd, pw, dumpState);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) {
- if (dumpState.onTitlePrinted()) pw.println();
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) {
dump(DumpState.DUMP_COMPILER_STATS, fd, pw, dumpState);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
- if (dumpState.onTitlePrinted()) pw.println();
- synchronized (mLock) {
- mSettings.dumpReadMessagesLPr(pw, dumpState);
+ if (dumpState.isDumping(DumpState.DUMP_MESSAGES)
+ && packageName == null) {
+ if (!checkin) {
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
+ synchronized (mLock) {
+ mSettings.dumpReadMessagesLPr(pw, dumpState);
+ }
+ pw.println();
+ pw.println("Package warning messages:");
+ dumpCriticalInfo(pw, null);
+ } else {
+ dumpCriticalInfo(pw, "msg,");
}
- pw.println();
- pw.println("Package warning messages:");
- dumpCriticalInfo(pw, null);
- }
-
- if (checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES)) {
- dumpCriticalInfo(pw, "msg,");
}
// PackageInstaller should be called outside of mPackages lock
- if (!checkin && dumpState.isDumping(DumpState.DUMP_INSTALLS) && packageName == null) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_INSTALLS)
+ && packageName == null) {
// XXX should handle packageName != null by dumping only install data that
// the given package is involved with.
- if (dumpState.onTitlePrinted()) pw.println();
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
mInstallerService.dump(new IndentingPrintWriter(pw, " ", 120));
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_APEX)) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_APEX)
+ && (packageName == null || mApexManager.isApexPackage(packageName))) {
mApexManager.dump(pw, packageName);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_PER_UID_READ_TIMEOUTS)
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_PER_UID_READ_TIMEOUTS)
&& packageName == null) {
- pw.println();
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
pw.println("Per UID read timeouts:");
pw.println(" Default timeouts flag: " + getDefaultTimeouts());
pw.println(" Known digesters list flag: " + getKnownDigestersList());
@@ -21408,7 +19714,12 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_SNAPSHOT_STATISTICS)) {
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_SNAPSHOT_STATISTICS)
+ && packageName == null) {
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
pw.println("Snapshot statistics");
if (!mSnapshotEnabled) {
pw.println(" Snapshots disabled");
@@ -21636,7 +19947,8 @@ public class PackageManagerService extends IPackageManager.Stub
try {
sm.prepareUserStorage(volumeUuid, user.id, user.serialNumber, flags);
synchronized (mInstallLock) {
- reconcileAppsDataLI(volumeUuid, user.id, flags, true /* migrateAppData */);
+ reconcileAppsDataLI(volumeUuid, user.id, flags, true /* migrateAppData */,
+ null);
}
} catch (IllegalStateException e) {
// Device was probably ejected, and we'll process that event momentarily
@@ -21825,21 +20137,32 @@ public class PackageManagerService extends IPackageManager.Stub
* <p>
* Verifies that directories exist and that ownership and labeling is
* correct for all installed apps on all mounted volumes.
+ *
+ * @param reconciledPackages A set that will be populated with package names that have
+ * successfully had their data reconciled. Any package names already
+ * contained will be skipped. Because this must be mutable when
+ * non-null, it is typed {@link ArraySet} to prevent accidental
+ * usage of {@link Collections#emptySet()}. Null can be passed if the
+ * caller doesn't need this functionality.
*/
- void reconcileAppsData(int userId, int flags, boolean migrateAppsData) {
+ @NonNull
+ void reconcileAppsData(int userId, int flags, boolean migrateAppsData,
+ @Nullable ArraySet<String> reconciledPackages) {
final StorageManager storage = mInjector.getSystemService(StorageManager.class);
for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
final String volumeUuid = vol.getFsUuid();
synchronized (mInstallLock) {
- reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppsData);
+ reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppsData,
+ reconciledPackages);
}
}
}
@GuardedBy("mInstallLock")
private void reconcileAppsDataLI(String volumeUuid, int userId, int flags,
- boolean migrateAppData) {
- reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppData, false /* onlyCoreApps */);
+ boolean migrateAppData, @Nullable ArraySet<String> reconciledPackages) {
+ reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppData, false /* onlyCoreApps */,
+ reconciledPackages);
}
/**
@@ -21854,7 +20177,8 @@ public class PackageManagerService extends IPackageManager.Stub
*/
@GuardedBy("mInstallLock")
private List<String> reconcileAppsDataLI(String volumeUuid, int userId, int flags,
- boolean migrateAppData, boolean onlyCoreApps) {
+ boolean migrateAppData, boolean onlyCoreApps,
+ @Nullable ArraySet<String> reconciledPackages) {
Slog.v(TAG, "reconcileAppsData for " + volumeUuid + " u" + userId + " 0x"
+ Integer.toHexString(flags) + " migrateAppData=" + migrateAppData);
List<String> result = onlyCoreApps ? new ArrayList<>() : null;
@@ -21917,6 +20241,9 @@ public class PackageManagerService extends IPackageManager.Stub
int preparedCount = 0;
for (PackageSetting ps : packages) {
final String packageName = ps.name;
+ if (reconciledPackages != null && reconciledPackages.contains(packageName)) {
+ continue;
+ }
if (ps.pkg == null) {
Slog.w(TAG, "Odd, missing scanned package " + packageName);
// TODO: might be due to legacy ASEC apps; we should circle back
@@ -21932,6 +20259,10 @@ public class PackageManagerService extends IPackageManager.Stub
if (ps.getInstalled(userId)) {
prepareAppDataAndMigrate(batch, ps.pkg, userId, flags, migrateAppData);
preparedCount++;
+
+ if (reconciledPackages != null) {
+ reconciledPackages.add(packageName);
+ }
}
}
executeBatchLI(batch);
@@ -22818,137 +21149,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- Pair<Integer, String> verifyReplacingVersionCode(PackageInfoLite pkgLite,
- long requiredInstalledVersionCode, int installFlags) {
- if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
- return verifyReplacingVersionCodeForApex(
- pkgLite, requiredInstalledVersionCode, installFlags);
- }
-
- String packageName = pkgLite.packageName;
- synchronized (mLock) {
- // Package which currently owns the data that the new package will own if installed.
- // If an app is uninstalled while keeping data (e.g. adb uninstall -k), installedPkg
- // will be null whereas dataOwnerPkg will contain information about the package
- // which was uninstalled while keeping its data.
- AndroidPackage dataOwnerPkg = mPackages.get(packageName);
- if (dataOwnerPkg == null) {
- PackageSetting ps = mSettings.getPackageLPr(packageName);
- if (ps != null) {
- dataOwnerPkg = ps.pkg;
- }
- }
-
- if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) {
- if (dataOwnerPkg == null) {
- String errorMsg = "Required installed version code was "
- + requiredInstalledVersionCode
- + " but package is not installed";
- Slog.w(TAG, errorMsg);
- return Pair.create(
- PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
- }
-
- if (dataOwnerPkg.getLongVersionCode() != requiredInstalledVersionCode) {
- String errorMsg = "Required installed version code was "
- + requiredInstalledVersionCode
- + " but actual installed version is "
- + dataOwnerPkg.getLongVersionCode();
- Slog.w(TAG, errorMsg);
- return Pair.create(
- PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
- }
- }
-
- if (dataOwnerPkg != null) {
- if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
- dataOwnerPkg.isDebuggable())) {
- try {
- checkDowngrade(dataOwnerPkg, pkgLite);
- } catch (PackageManagerException e) {
- String errorMsg = "Downgrade detected: " + e.getMessage();
- Slog.w(TAG, errorMsg);
- return Pair.create(
- PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg);
- }
- }
- }
- }
- return Pair.create(PackageManager.INSTALL_SUCCEEDED, null);
- }
-
- private Pair<Integer, String> verifyReplacingVersionCodeForApex(PackageInfoLite pkgLite,
- long requiredInstalledVersionCode, int installFlags) {
- String packageName = pkgLite.packageName;
-
- final PackageInfo activePackage = mApexManager.getPackageInfo(packageName,
- ApexManager.MATCH_ACTIVE_PACKAGE);
- if (activePackage == null) {
- String errorMsg = "Attempting to install new APEX package " + packageName;
- Slog.w(TAG, errorMsg);
- return Pair.create(PackageManager.INSTALL_FAILED_PACKAGE_CHANGED, errorMsg);
- }
-
- final long activeVersion = activePackage.getLongVersionCode();
- if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST
- && activeVersion != requiredInstalledVersionCode) {
- String errorMsg = "Installed version of APEX package " + packageName
- + " does not match required. Active version: " + activeVersion
- + " required: " + requiredInstalledVersionCode;
- Slog.w(TAG, errorMsg);
- return Pair.create(PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION, errorMsg);
- }
-
- final boolean isAppDebuggable = (activePackage.applicationInfo.flags
- & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
- final long newVersionCode = pkgLite.getLongVersionCode();
- if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags, isAppDebuggable)
- && newVersionCode < activeVersion) {
- String errorMsg = "Downgrade of APEX package " + packageName
- + " is not allowed. Active version: " + activeVersion
- + " attempted: " + newVersionCode;
- Slog.w(TAG, errorMsg);
- return Pair.create(PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg);
- }
-
- return Pair.create(PackageManager.INSTALL_SUCCEEDED, null);
- }
-
- /**
- * Check and throw if the given before/after packages would be considered a
- * downgrade.
- */
- private static void checkDowngrade(AndroidPackage before, PackageInfoLite after)
- throws PackageManagerException {
- if (after.getLongVersionCode() < before.getLongVersionCode()) {
- throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
- "Update version code " + after.versionCode + " is older than current "
- + before.getLongVersionCode());
- } else if (after.getLongVersionCode() == before.getLongVersionCode()) {
- if (after.baseRevisionCode < before.getBaseRevisionCode()) {
- throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
- "Update base revision code " + after.baseRevisionCode
- + " is older than current " + before.getBaseRevisionCode());
- }
-
- if (!ArrayUtils.isEmpty(after.splitNames)) {
- for (int i = 0; i < after.splitNames.length; i++) {
- final String splitName = after.splitNames[i];
- final int j = ArrayUtils.indexOf(before.getSplitNames(), splitName);
- if (j != -1) {
- if (after.splitRevisionCodes[i] < before.getSplitRevisionCodes()[j]) {
- throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
- "Update split " + splitName + " revision code "
- + after.splitRevisionCodes[i]
- + " is older than current "
- + before.getSplitRevisionCodes()[j]);
- }
- }
- }
- }
- }
- }
-
private static class MoveCallbacks extends Handler {
private static final int MSG_CREATED = 1;
private static final int MSG_STATUS_CHANGED = 2;
@@ -24560,7 +22760,7 @@ public class PackageManagerService extends IPackageManager.Stub
return mComputer.getPackageSetting(packageName);
}
- private PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
+ PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
return mComputer.getPackageSettingInternal(packageName, callingUid);
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 717f3d57ec38..d9c4d316f948 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -455,7 +455,7 @@ public abstract class PackageSettingBase extends SettingBase {
return state.suspendParams != null && state.suspendParams.containsKey(suspendingPackage);
}
- void addOrUpdateSuspension(String suspendingPackage, SuspendDialogInfo dialogInfo,
+ boolean addOrUpdateSuspension(String suspendingPackage, SuspendDialogInfo dialogInfo,
PersistableBundle appExtras, PersistableBundle launcherExtras, int userId) {
final PackageUserState existingUserState = modifyUserState(userId);
final PackageUserState.SuspendParams newSuspendParams =
@@ -464,21 +464,27 @@ public abstract class PackageSettingBase extends SettingBase {
if (existingUserState.suspendParams == null) {
existingUserState.suspendParams = new ArrayMap<>();
}
- existingUserState.suspendParams.put(suspendingPackage, newSuspendParams);
+ final PackageUserState.SuspendParams oldSuspendParams =
+ existingUserState.suspendParams.put(suspendingPackage, newSuspendParams);
existingUserState.suspended = true;
onChanged();
+ return !Objects.equals(oldSuspendParams, newSuspendParams);
}
- void removeSuspension(String suspendingPackage, int userId) {
+ boolean removeSuspension(String suspendingPackage, int userId) {
+ boolean wasModified = false;
final PackageUserState existingUserState = modifyUserState(userId);
if (existingUserState.suspendParams != null) {
- existingUserState.suspendParams.remove(suspendingPackage);
+ if (existingUserState.suspendParams.remove(suspendingPackage) != null) {
+ wasModified = true;
+ }
if (existingUserState.suspendParams.size() == 0) {
existingUserState.suspendParams = null;
}
}
existingUserState.suspended = (existingUserState.suspendParams != null);
onChanged();
+ return wasModified;
}
void removeSuspension(Predicate<String> suspendingPackagePredicate, int userId) {
diff --git a/services/core/java/com/android/server/pm/ScanPartition.java b/services/core/java/com/android/server/pm/ScanPartition.java
new file mode 100644
index 000000000000..e1d2b3bcfefe
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ScanPartition.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static com.android.server.pm.PackageManagerService.SCAN_AS_ODM;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_OEM;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_PRODUCT;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM_EXT;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_VENDOR;
+
+import android.annotation.NonNull;
+import android.content.pm.PackagePartitions;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+
+/**
+ * List of partitions to be scanned during system boot
+ */
+@VisibleForTesting
+public class ScanPartition extends PackagePartitions.SystemPartition {
+ @PackageManagerService.ScanFlags
+ public final int scanFlag;
+
+ public ScanPartition(@NonNull PackagePartitions.SystemPartition partition) {
+ super(partition);
+ scanFlag = scanFlagForPartition(partition);
+ }
+
+ /**
+ * Creates a partition containing the same folders as the original partition but with a
+ * different root folder. The new partition will include the scan flags of the original
+ * partition along with any specified additional scan flags.
+ */
+ public ScanPartition(@NonNull File folder, @NonNull ScanPartition original,
+ @PackageManagerService.ScanFlags int additionalScanFlag) {
+ super(folder, original);
+ this.scanFlag = original.scanFlag | additionalScanFlag;
+ }
+
+ private static int scanFlagForPartition(PackagePartitions.SystemPartition partition) {
+ switch (partition.type) {
+ case PackagePartitions.PARTITION_SYSTEM:
+ return 0;
+ case PackagePartitions.PARTITION_VENDOR:
+ return SCAN_AS_VENDOR;
+ case PackagePartitions.PARTITION_ODM:
+ return SCAN_AS_ODM;
+ case PackagePartitions.PARTITION_OEM:
+ return SCAN_AS_OEM;
+ case PackagePartitions.PARTITION_PRODUCT:
+ return SCAN_AS_PRODUCT;
+ case PackagePartitions.PARTITION_SYSTEM_EXT:
+ return SCAN_AS_SYSTEM_EXT;
+ default:
+ throw new IllegalStateException("Unable to determine scan flag for "
+ + partition.getFolder());
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getFolder().getAbsolutePath() + ":" + scanFlag;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a854aa056238..b111bbfcb80b 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3089,8 +3089,7 @@ public final class Settings implements Watchable, Snappable {
// Read preferred apps from .../etc/preferred-apps directories.
int size = PackageManagerService.SYSTEM_PARTITIONS.size();
for (int index = 0; index < size; index++) {
- PackageManagerService.ScanPartition partition =
- PackageManagerService.SYSTEM_PARTITIONS.get(index);
+ ScanPartition partition = PackageManagerService.SYSTEM_PARTITIONS.get(index);
File preferredDir = new File(partition.getFolder(), "etc/preferred-apps");
if (!preferredDir.exists() || !preferredDir.isDirectory()) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index e8182e07ba4d..40e05263406e 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4805,7 +4805,7 @@ public class UserManagerService extends IUserManager.Stub {
mUserDataPreparer.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_DE);
t.traceEnd();
t.traceBegin("reconcileAppsData");
- mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_DE, migrateAppsData);
+ mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_DE, migrateAppsData, null);
t.traceEnd();
if (userId != UserHandle.USER_SYSTEM) {
@@ -4821,11 +4821,14 @@ public class UserManagerService extends IUserManager.Stub {
/**
* Called right before a user is unlocked. This gives us a chance to prepare
* app storage.
+ *
+ * @return set of packages that reconciled app data
*/
- public void onBeforeUnlockUser(@UserIdInt int userId) {
+ @NonNull public ArraySet<String> onBeforeUnlockUser(@UserIdInt int userId) {
UserInfo userInfo = getUserInfo(userId);
if (userInfo == null) {
- return;
+ // PMS requires mutable set, so the API uses ArraySet to prevent Collections.emptySet()
+ return new ArraySet<>();
}
final int userSerial = userInfo.serialNumber;
// Migrate only if build fingerprints mismatch
@@ -4836,8 +4839,33 @@ public class UserManagerService extends IUserManager.Stub {
mUserDataPreparer.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_CE);
t.traceEnd();
- t.traceBegin("reconcileAppsData-" + userId);
- mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_CE, migrateAppsData);
+ final ArraySet<String> reconciledPackages = new ArraySet<>();
+ t.traceBegin("reconcileAppsDataFirstPass-" + userId);
+ mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_CE, migrateAppsData,
+ reconciledPackages);
+ t.traceEnd();
+ return reconciledPackages;
+ }
+
+ /**
+ * Called right after a user state is moved to {@link UserState#STATE_RUNNING_UNLOCKING}. This
+ * gives us a chance to reconcile app data for apps installed since
+ * {@link #onBeforeUnlockUser(int)} was called.
+ *
+ * @param previouslyReconciledPackages the result from {@link #onBeforeUnlockUser(int)}
+ */
+ public void onUserStateRunningUnlocking(@UserIdInt int userId,
+ @NonNull ArraySet<String> previouslyReconciledPackages) {
+ final UserInfo userInfo = getUserInfo(userId);
+ if (userInfo == null) {
+ return;
+ }
+ // Migrate only if build fingerprints mismatch
+ boolean migrateAppsData = !Build.FINGERPRINT.equals(userInfo.lastLoggedInFingerprint);
+ final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+ t.traceBegin("reconcileAppsDataSecondPass-" + userId);
+ mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_CE, migrateAppsData,
+ previouslyReconciledPackages);
t.traceEnd();
}
diff --git a/services/core/java/com/android/server/pm/VerificationParams.java b/services/core/java/com/android/server/pm/VerificationParams.java
index 3c499de9ea46..dae4038626d8 100644
--- a/services/core/java/com/android/server/pm/VerificationParams.java
+++ b/services/core/java/com/android/server/pm/VerificationParams.java
@@ -131,13 +131,12 @@ final class VerificationParams extends HandlerParams {
private String mErrorMessage = null;
final PackageLite mPackageLite;
- final PackageManagerService mPm;
VerificationParams(UserHandle user, File stagedDir, IPackageInstallObserver2 observer,
PackageInstaller.SessionParams sessionParams, InstallSource installSource,
int installerUid, SigningDetails signingDetails, int sessionId, PackageLite lite,
PackageManagerService pm) {
- super(user);
+ super(user, pm);
mOriginInfo = OriginInfo.fromStagedFile(stagedDir);
mObserver = observer;
mInstallFlags = sessionParams.installFlags;
@@ -155,7 +154,6 @@ final class VerificationParams extends HandlerParams {
? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
mSessionId = sessionId;
mPackageLite = lite;
- mPm = pm;
}
@Override
@@ -168,7 +166,7 @@ final class VerificationParams extends HandlerParams {
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext,
mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags, mPackageAbiOverride);
- Pair<Integer, String> ret = mPm.verifyReplacingVersionCode(
+ Pair<Integer, String> ret = verifyReplacingVersionCode(
pkgLite, mRequiredInstalledVersionCode, mInstallFlags);
setReturnCode(ret.first, ret.second);
if (mRet != INSTALL_SUCCEEDED) {
@@ -707,7 +705,7 @@ final class VerificationParams extends HandlerParams {
public void verifyStage(List<VerificationParams> children)
throws PackageManagerException {
final MultiPackageVerificationParams params =
- new MultiPackageVerificationParams(this, children);
+ new MultiPackageVerificationParams(this, children, mPm);
mPm.mHandler.post(params::startCopy);
}
@@ -720,9 +718,9 @@ final class VerificationParams extends HandlerParams {
private final List<VerificationParams> mChildParams;
private final Map<VerificationParams, Integer> mVerificationState;
- MultiPackageVerificationParams(VerificationParams parent, List<VerificationParams> children)
- throws PackageManagerException {
- super(parent.getUser());
+ MultiPackageVerificationParams(VerificationParams parent, List<VerificationParams> children,
+ PackageManagerService pm) throws PackageManagerException {
+ super(parent.getUser(), pm);
if (children.size() == 0) {
throw new PackageManagerException("No child sessions found!");
}
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index 11aed8d77646..75f37257e35e 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -476,9 +476,10 @@ public final class Permission {
r.append("DUP:");
r.append(permissionInfo.name);
}
- if (permission.isRuntime() && (ownerChanged || wasNonRuntime)) {
- // If this is a runtime permission and the owner has changed, or this wasn't a runtime
- // permission, then permission state should be cleaned up
+ if ((permission.isInternal() && ownerChanged)
+ || (permission.isRuntime() && (ownerChanged || wasNonRuntime))) {
+ // If this is an internal/runtime permission and the owner has changed, or this wasn't a
+ // runtime permission, then permission state should be cleaned up.
permission.mDefinitionChanged = true;
}
if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
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 74497f72ff21..904e88920824 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1655,7 +1655,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
isRolePermission = permission.isRole();
}
final boolean mayRevokeRolePermission = isRolePermission
- && mayManageRolePermission(callingUid);
+ // Allow ourselves to revoke role permissions due to definition changes.
+ && (callingUid == Process.myUid() || mayManageRolePermission(callingUid));
final boolean isRuntimePermission;
synchronized (mLock) {
@@ -2333,11 +2334,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
for (int permNum = 0; permNum < numPermissions; permNum++) {
final String permName = permissionsToRevoke.get(permNum);
+ final boolean isInternalPermission;
synchronized (mLock) {
final Permission bp = mRegistry.getPermission(permName);
- if (bp == null || !bp.isRuntime()) {
+ if (bp == null || !(bp.isInternal() || bp.isRuntime())) {
continue;
}
+ isInternalPermission = bp.isInternal();
}
mPackageManagerInt.forEachPackage(pkg -> {
final String packageName = pkg.getPackageName();
@@ -2357,12 +2360,18 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (permissionState == PackageManager.PERMISSION_GRANTED
&& (flags & flagMask) == 0) {
final int uid = UserHandle.getUid(userId, appId);
- EventLog.writeEvent(0x534e4554, "154505240", uid,
- "Revoking permission " + permName + " from package "
- + packageName + " due to definition change");
- EventLog.writeEvent(0x534e4554, "168319670", uid,
- "Revoking permission " + permName + " from package "
- + packageName + " due to definition change");
+ if (isInternalPermission) {
+ EventLog.writeEvent(0x534e4554, "195338390", uid,
+ "Revoking permission " + permName + " from package "
+ + packageName + " due to definition change");
+ } else {
+ EventLog.writeEvent(0x534e4554, "154505240", uid,
+ "Revoking permission " + permName + " from package "
+ + packageName + " due to definition change");
+ EventLog.writeEvent(0x534e4554, "168319670", uid,
+ "Revoking permission " + permName + " from package "
+ + packageName + " due to definition change");
+ }
Slog.e(TAG, "Revoking permission " + permName + " from package "
+ packageName + " due to definition change");
try {
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 83085ccb7d8c..1ebb722b022f 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -114,6 +114,8 @@ class TvInputHardwareManager implements TvInputHal.Callback {
private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray();
private final List<Message> mPendingHdmiDeviceEvents = new LinkedList<>();
+ private final List<Message> mPendingTvinputInfoEvents = new LinkedList<>();
+
// Calls to mListener should happen here.
private final Handler mHandler = new ListenerHandler();
@@ -229,7 +231,16 @@ class TvInputHardwareManager implements TvInputHal.Callback {
connection.getInputStateLocked(), 0, inputId).sendToTarget();
}
}
- }
+ } else {
+ Message msg = mHandler.obtainMessage(ListenerHandler.TVINPUT_INFO_ADDED,
+ deviceId, cableConnectionStatus, connection);
+ for (Iterator<Message> it = mPendingTvinputInfoEvents.iterator(); it.hasNext();) {
+ if (it.next().arg1 == deviceId) {
+ it.remove();
+ }
+ }
+ mPendingTvinputInfoEvents.add(msg);
+ }
ITvInputHardwareCallback callback = connection.getCallbackLocked();
if (callback != null) {
try {
@@ -288,6 +299,8 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
mHardwareInputIdMap.put(deviceId, info.getId());
mInputMap.put(info.getId(), info);
+ processPendingTvInputInfoEventsLocked();
+ Slog.d(TAG,"deviceId ="+ deviceId+", tvinputinfo = "+info);
// Process pending state changes
@@ -530,6 +543,20 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
}
+
+ private void processPendingTvInputInfoEventsLocked() {
+ for (Iterator<Message> it = mPendingTvinputInfoEvents.iterator(); it.hasNext(); ) {
+ Message msg = it.next();
+ int deviceId = msg.arg1;
+ String inputId = mHardwareInputIdMap.get(deviceId);
+ if (inputId != null) {
+ msg.sendToTarget();
+ it.remove();
+ }
+ }
+ }
+
+
private void updateVolume() {
mCurrentMaxIndex = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
mCurrentIndex = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
@@ -1182,6 +1209,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
private static final int HDMI_DEVICE_ADDED = 4;
private static final int HDMI_DEVICE_REMOVED = 5;
private static final int HDMI_DEVICE_UPDATED = 6;
+ private static final int TVINPUT_INFO_ADDED = 7;
@Override
public final void handleMessage(Message msg) {
@@ -1226,6 +1254,29 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
break;
}
+ case TVINPUT_INFO_ADDED: {
+ int deviceId = msg.arg1;
+ int cableConnectionStatus = msg.arg2;
+ Connection connection =(Connection)msg.obj;
+
+ int previousConfigsLength = connection.getConfigsLengthLocked();
+ int previousCableConnectionStatus = connection.getInputStateLocked();
+ String inputId = mHardwareInputIdMap.get(deviceId);
+
+ if (inputId != null) {
+ if (connection.updateCableConnectionStatusLocked(cableConnectionStatus)) {
+ if (previousCableConnectionStatus != connection.getInputStateLocked()) {
+ mListener.onStateChanged(inputId, connection.getInputStateLocked());
+ }
+ } else {
+ if ((previousConfigsLength == 0)
+ != (connection.getConfigsLengthLocked() == 0)) {
+ mListener.onStateChanged(inputId, connection.getInputStateLocked());
+ }
+ }
+ }
+ break;
+ }
default: {
Slog.w(TAG, "Unhandled message: " + msg);
break;
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 36a854e5374c..28947083854b 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -2304,10 +2304,9 @@ public final class TvInputManagerService extends SystemService {
public void requestChannelBrowsable(Uri channelUri, int userId)
throws RemoteException {
final String callingPackageName = getCallingPackageName();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, "requestChannelBrowsable");
final long identity = Binder.clearCallingIdentity();
- final int callingUid = Binder.getCallingUid();
- final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
- userId, "requestChannelBrowsable");
try {
Intent intent = new Intent(TvContract.ACTION_CHANNEL_BROWSABLE_REQUESTED);
List<ResolveInfo> list = getContext().getPackageManager()
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 0efc940dff93..c5c0325e5590 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -1380,8 +1380,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
// At this point we have an externally controlled vibration playing already.
// Since the interface defines that only one externally controlled vibration can
// play at a time, we need to first mute the ongoing vibration and then return
- // a scale from this function for the new one. Ee can be assured that the
- // ongoing it will be muted in favor of the new vibration.
+ // a scale from this function for the new one, so we can be assured that the
+ // ongoing will be muted in favor of the new vibration.
//
// Note that this doesn't support multiple concurrent external controls, as we
// would need to mute the old one still if it came from a different controller.
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index cf6a38ff33c6..3d9d1f8985f5 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2595,6 +2595,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return task != null ? task.getOrganizedTask() : null;
}
+ /** Returns the organized parent {@link TaskFragment}. */
+ @Nullable
+ TaskFragment getOrganizedTaskFragment() {
+ final TaskFragment parent = getTaskFragment();
+ return parent != null ? parent.getOrganizedTaskFragment() : null;
+ }
+
@Override
@Nullable
TaskDisplayArea getDisplayArea() {
@@ -4307,7 +4314,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// The activity now gets access to the data associated with this Intent.
mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants,
getUriPermissionsLocked());
- final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
+ final ReferrerIntent rintent = new ReferrerIntent(intent, getFilteredReferrer(referrer));
boolean unsent = true;
final boolean isTopActivityWhileSleeping = isTopRunningActivity() && isSleeping();
@@ -8413,7 +8420,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
startFreezingScreenLocked(globalChanges);
}
forceNewConfig = false;
- preserveWindow &= isResizeOnlyChange(changes);
+ // Do not preserve window if it is freezing screen because the original window won't be
+ // able to update drawn state that causes freeze timeout.
+ preserveWindow &= isResizeOnlyChange(changes) && !mFreezingScreen;
final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged());
if (hasResizeChange) {
final boolean isDragResizing = task.isDragResizing();
@@ -8817,6 +8826,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
/**
+ * Gets the referrer package name with respect to package visibility. This method returns null
+ * if the given package is not visible to this activity.
+ */
+ String getFilteredReferrer(String referrerPackage) {
+ if (referrerPackage == null || (!referrerPackage.equals(packageName)
+ && mWmService.mPmInternal.filterAppAccess(
+ referrerPackage, info.applicationInfo.uid, mUserId))) {
+ return null;
+ }
+ return referrerPackage;
+ }
+
+ /**
* Determines whether this ActivityRecord can turn the screen on. It checks whether the flag
* {@link ActivityRecord#getTurnScreenOnFlag} is set and checks whether the ActivityRecord
* should be visible depending on Keyguard state.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index e593c1c1e656..ea242bb28495 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -857,9 +857,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
- r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
- r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
- r.takeOptions(), isTransitionForward,
+ r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
+ proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
+ results, newIntents, r.takeOptions(), isTransitionForward,
proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
r.createFixedRotationAdjustmentsIfNeeded(), r.shareableActivityToken,
r.getLaunchedFromBubble(), fragmentToken));
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 544cade6578c..7a42351c33c1 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -86,6 +86,7 @@ import android.view.WindowManager.TransitionFlags;
import android.view.WindowManager.TransitionOldType;
import android.view.WindowManager.TransitionType;
import android.view.animation.Animation;
+import android.window.ITaskFragmentOrganizer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
@@ -233,7 +234,11 @@ public class AppTransitionController {
final ActivityRecord topChangingApp =
getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
- overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
+
+ // Check if there is any override
+ if (!overrideWithTaskFragmentRemoteAnimation(transit, activityTypes)) {
+ overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
+ }
final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
|| containsVoiceInteraction(mDisplayContent.mOpeningApps);
@@ -483,6 +488,7 @@ public class AppTransitionController {
return TYPE_NONE;
}
+ @Nullable
private static WindowManager.LayoutParams getAnimLp(ActivityRecord activity) {
final WindowState mainWindow = activity != null ? activity.findMainWindow() : null;
return mainWindow != null ? mainWindow.mAttrs : null;
@@ -506,6 +512,61 @@ public class AppTransitionController {
}
/**
+ * Overrides the pending transition with the remote animation defined by the
+ * {@link ITaskFragmentOrganizer} if all windows in the transition are children of
+ * {@link TaskFragment} that are organized by the same organizer.
+ *
+ * @return {@code true} if the transition is overridden.
+ */
+ @VisibleForTesting
+ boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit,
+ ArraySet<Integer> activityTypes) {
+ final ArrayList<WindowContainer> allWindows = new ArrayList<>();
+ allWindows.addAll(mDisplayContent.mClosingApps);
+ allWindows.addAll(mDisplayContent.mOpeningApps);
+ allWindows.addAll(mDisplayContent.mChangingContainers);
+
+ // Find the common TaskFragmentOrganizer of all windows.
+ ITaskFragmentOrganizer organizer = null;
+ for (int i = allWindows.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = getAppFromContainer(allWindows.get(i));
+ if (r == null) {
+ return false;
+ }
+ final TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment();
+ final ITaskFragmentOrganizer curOrganizer = organizedTaskFragment != null
+ ? organizedTaskFragment.getTaskFragmentOrganizer()
+ : null;
+ if (curOrganizer == null) {
+ // All windows must below an organized TaskFragment.
+ return false;
+ }
+ if (organizer == null) {
+ organizer = curOrganizer;
+ } else if (!organizer.asBinder().equals(curOrganizer.asBinder())) {
+ // They must be controlled by the same organizer.
+ return false;
+ }
+ }
+
+ final RemoteAnimationDefinition definition = organizer != null
+ ? mDisplayContent.mAtmService.mTaskFragmentOrganizerController
+ .getRemoteAnimationDefinition(organizer)
+ : null;
+ final RemoteAnimationAdapter adapter = definition != null
+ ? definition.getAdapter(transit, activityTypes)
+ : null;
+ if (adapter == null) {
+ return false;
+ }
+ mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(adapter);
+ ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+ "Override with TaskFragment remote animation for transit=%s",
+ AppTransition.appTransitionOldToString(transit));
+ return true;
+ }
+
+ /**
* Overrides the pending transition with the remote animation defined for the transition in the
* set of defined remote animations in the app window token.
*/
@@ -524,13 +585,14 @@ public class AppTransitionController {
}
static ActivityRecord getAppFromContainer(WindowContainer wc) {
- return wc.asTask() != null ? wc.asTask().getTopNonFinishingActivity()
+ return wc.asTaskFragment() != null ? wc.asTaskFragment().getTopNonFinishingActivity()
: wc.asActivityRecord();
}
/**
* @return The window token that determines the animation theme.
*/
+ @Nullable
private ActivityRecord findAnimLayoutParamsToken(@TransitionOldType int transit,
ArraySet<Integer> activityTypes) {
ActivityRecord result;
@@ -543,7 +605,7 @@ public class AppTransitionController {
w -> w.getRemoteAnimationDefinition() != null
&& w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
if (result != null) {
- return getAppFromContainer(result);
+ return result;
}
result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
w -> w.fillsParent() && w.findMainWindow() != null);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 3627ad1e313d..db5e3d0e8c93 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3133,6 +3133,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return mScreenRotationAnimation;
}
+ /** If the display is in transition, there should be a screenshot covering it. */
+ @Override
+ boolean inTransition() {
+ return mScreenRotationAnimation != null || super.inTransition();
+ }
+
@Override
public void dumpDebug(ProtoOutputStream proto, long fieldId,
@WindowTraceLogLevel int logLevel) {
diff --git a/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
index 92baadf5ee69..5e8d795ce955 100644
--- a/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
+++ b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
@@ -22,12 +22,12 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Resources;
import android.provider.DeviceConfig;
+import android.provider.DeviceConfigInterface;
import android.util.ArraySet;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
-import com.android.server.utils.DeviceConfigInterface;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 0b44c80bc098..f2e6abcaade9 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -580,9 +580,12 @@ final class InputMonitor {
if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) {
if (recentsAnimationController.updateInputConsumerForApp(
mRecentsAnimationInputConsumer.mWindowHandle)) {
- mRecentsAnimationInputConsumer.show(mInputTransaction,
- recentsAnimationController.getHighestLayerWindow());
- mAddRecentsAnimationInputConsumerHandle = false;
+ final WindowState highestLayerWindow =
+ recentsAnimationController.getHighestLayerWindow();
+ if (highestLayerWindow != null) {
+ mRecentsAnimationInputConsumer.show(mInputTransaction, highestLayerWindow);
+ mAddRecentsAnimationInputConsumerHandle = false;
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index f3e52f28ba8b..f93e08531b67 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -22,7 +22,7 @@ import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_INSETS;
import static com.android.server.wm.InsetsSourceProviderProto.CAPTURED_LEASH;
import static com.android.server.wm.InsetsSourceProviderProto.CLIENT_VISIBLE;
import static com.android.server.wm.InsetsSourceProviderProto.CONTROL;
@@ -164,7 +164,8 @@ class InsetsSourceProvider {
mWin.cancelAnimation();
mWin.mProvidedInsetsSources.remove(mSource.getType());
}
- ProtoLog.d(WM_DEBUG_IME, "InsetsSource setWin %s", win);
+ ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "InsetsSource setWin %s for type %s", win,
+ InsetsState.typeToString(mSource.getType()));
mWin = win;
mFrameProvider = frameProvider;
mImeFrameProvider = imeFrameProvider;
@@ -343,7 +344,7 @@ class InsetsSourceProvider {
updateVisibility();
mControl = new InsetsSourceControl(mSource.getType(), leash, surfacePosition,
mSource.calculateInsets(mWin.getBounds(), true /* ignoreVisibility */));
- ProtoLog.d(WM_DEBUG_IME,
+ ProtoLog.d(WM_DEBUG_WINDOW_INSETS,
"InsetsSource Control %s for target %s", mControl, mControlTarget);
}
@@ -392,8 +393,9 @@ class InsetsSourceProvider {
protected void updateVisibility() {
mSource.setVisible(mServerVisible && (isMirroredSource() || mClientVisible));
- ProtoLog.d(WM_DEBUG_IME,
- "InsetsSource updateVisibility serverVisible: %s clientVisible: %s",
+ ProtoLog.d(WM_DEBUG_WINDOW_INSETS,
+ "InsetsSource updateVisibility for %s, serverVisible: %s clientVisible: %s",
+ InsetsState.typeToString(mSource.getType()),
mServerVisible, mClientVisible);
}
@@ -539,7 +541,7 @@ class InsetsSourceProvider {
t.setAlpha(animationLeash, 1 /* alpha */);
t.hide(animationLeash);
}
- ProtoLog.i(WM_DEBUG_IME,
+ ProtoLog.i(WM_DEBUG_WINDOW_INSETS,
"ControlAdapter startAnimation mSource: %s controlTarget: %s", mSource,
mControlTarget);
@@ -555,7 +557,7 @@ class InsetsSourceProvider {
mControlTarget = null;
mAdapter = null;
setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
- ProtoLog.i(WM_DEBUG_IME,
+ ProtoLog.i(WM_DEBUG_WINDOW_INSETS,
"ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
mSource, mControlTarget);
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 6f3edbcff4c0..4a8c36f9bc47 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -375,7 +375,7 @@ class KeyguardController {
// TODO(b/113840485): Handle app transition for individual display, and apply occluded
// state change to secondary displays.
// For now, only default display fully supports occluded change. Other displays only
- // updates keygaurd sleep token on that display.
+ // updates keyguard sleep token on that display.
if (displayId != DEFAULT_DISPLAY) {
updateKeyguardSleepToken(displayId);
return;
@@ -390,15 +390,6 @@ class KeyguardController {
isDisplayOccluded(DEFAULT_DISPLAY)
? TRANSIT_KEYGUARD_OCCLUDE
: TRANSIT_KEYGUARD_UNOCCLUDE, 0 /* flags */);
- // When the occluding activity also turns on the display, visibility of the activity
- // can be committed before KEYGUARD_OCCLUDE transition is handled.
- // Set mRequestForceTransition flag to make sure that the app transition animation
- // is applied for such case.
- // TODO(b/194243906): Fix this before enabling the remote keyguard animation.
- if (WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation
- && topActivity != null) {
- topActivity.mRequestForceTransition = true;
- }
updateKeyguardSleepToken(DEFAULT_DISPLAY);
mWindowManager.executeAppTransition();
} finally {
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index d440a14d6199..d1460f41cad6 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -729,7 +729,12 @@ class ScreenRotationAnimation {
mScreenshotRotationAnimator = null;
mRotateScreenAnimator = null;
mService.mAnimator.mBulkUpdateParams |= WindowSurfacePlacer.SET_UPDATE_ROTATION;
- kill();
+ if (mDisplayContent.getRotationAnimation() == ScreenRotationAnimation.this) {
+ // It also invokes kill().
+ mDisplayContent.setRotationAnimation(null);
+ } else {
+ kill();
+ }
mService.updateRotation(false, false);
}
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 242693b758fb..1b72826fba9b 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -2014,6 +2014,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|| mDisplayContent == null
|| mTaskFragmentOrganizer == null
|| getSurfaceControl() == null
+ // The change transition will be covered by display.
+ || mDisplayContent.inTransition()
|| !isVisible()) {
return false;
}
@@ -2095,7 +2097,6 @@ class TaskFragment extends WindowContainer<WindowContainer> {
}
@Nullable
- @VisibleForTesting
ITaskFragmentOrganizer getTaskFragmentOrganizer() {
return mTaskFragmentOrganizer;
}
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 690f67c25cfe..30d2a323aabe 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -30,6 +30,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Slog;
+import android.view.RemoteAnimationDefinition;
import android.view.SurfaceControl;
import android.window.ITaskFragmentOrganizer;
import android.window.ITaskFragmentOrganizerController;
@@ -81,6 +82,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs =
new WeakHashMap<>();
+ /**
+ * @see android.window.TaskFragmentOrganizer#registerRemoteAnimations(
+ * RemoteAnimationDefinition)
+ */
+ @Nullable
+ private RemoteAnimationDefinition mRemoteAnimationDefinition;
+
TaskFragmentOrganizerState(ITaskFragmentOrganizer organizer) {
mOrganizer = organizer;
try {
@@ -245,6 +253,61 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
}
}
+ @Override
+ public void registerRemoteAnimations(ITaskFragmentOrganizer organizer,
+ RemoteAnimationDefinition definition) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
+ "Register remote animations for organizer=%s uid=%d pid=%d",
+ organizer.asBinder(), uid, pid);
+ final TaskFragmentOrganizerState organizerState =
+ mTaskFragmentOrganizerState.get(organizer.asBinder());
+ if (organizerState == null) {
+ throw new IllegalStateException("The organizer hasn't been registered.");
+ }
+ if (organizerState.mRemoteAnimationDefinition != null) {
+ throw new IllegalStateException(
+ "The organizer has already registered remote animations="
+ + organizerState.mRemoteAnimationDefinition);
+ }
+
+ definition.setCallingPidUid(pid, uid);
+ organizerState.mRemoteAnimationDefinition = definition;
+ }
+ }
+
+ @Override
+ public void unregisterRemoteAnimations(ITaskFragmentOrganizer organizer) {
+ final int pid = Binder.getCallingPid();
+ final long uid = Binder.getCallingUid();
+ synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
+ "Unregister remote animations for organizer=%s uid=%d pid=%d",
+ organizer.asBinder(), uid, pid);
+ final TaskFragmentOrganizerState organizerState =
+ mTaskFragmentOrganizerState.get(organizer.asBinder());
+ if (organizerState == null) {
+ Slog.e(TAG, "The organizer hasn't been registered.");
+ return;
+ }
+
+ organizerState.mRemoteAnimationDefinition = null;
+ }
+ }
+
+ /** Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. */
+ @Nullable
+ public RemoteAnimationDefinition getRemoteAnimationDefinition(
+ ITaskFragmentOrganizer organizer) {
+ synchronized (mGlobalLock) {
+ final TaskFragmentOrganizerState organizerState =
+ mTaskFragmentOrganizerState.get(organizer.asBinder());
+ return organizerState != null ? organizerState.mRemoteAnimationDefinition : null;
+ }
+ }
+
void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) {
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
if (!state.addTaskFragment(taskFragment)) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index b6c8e13bb74f..aec7cab2a1ec 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -987,6 +987,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return mDisplayContent != null && mDisplayContent.mChangingContainers.contains(this);
}
+ boolean inTransition() {
+ return mWmService.mAtmService.getTransitionController().inTransition(this);
+ }
+
void sendAppVisibilityToClients() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java
index a5ebf9ac74b9..bdbcd166dc0b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerConstants.java
+++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java
@@ -21,9 +21,9 @@ import static android.provider.AndroidDeviceConfig.KEY_SYSTEM_GESTURE_EXCLUSION_
import android.provider.AndroidDeviceConfig;
import android.provider.DeviceConfig;
+import android.provider.DeviceConfigInterface;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.utils.DeviceConfigInterface;
import java.io.PrintWriter;
import java.util.Objects;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f24d74a2e356..a373d8d284b9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -206,6 +206,7 @@ import android.os.SystemService;
import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.provider.DeviceConfigInterface;
import android.provider.Settings;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
@@ -300,7 +301,6 @@ import com.android.server.input.InputManagerService;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
import com.android.server.power.ShutdownThread;
-import com.android.server.utils.DeviceConfigInterface;
import com.android.server.utils.PriorityDump;
import java.io.BufferedWriter;
@@ -8113,9 +8113,8 @@ public class WindowManagerService extends IWindowManager.Stub
boolean animateStarting = false;
while (timeoutRemaining > 0) {
// Waiting until all starting windows has finished animating.
- animateStarting = mRoot.forAllActivities(a -> {
- return a.hasStartingWindow();
- });
+ animateStarting = !mAtmService.getTransitionController().isShellTransitionsEnabled()
+ && mRoot.forAllActivities(ActivityRecord::hasStartingWindow);
boolean isAnimating = mAnimator.isAnimationScheduled()
|| mRoot.isAnimating(TRANSITION | CHILDREN, ANIMATION_TYPE_ALL)
|| animateStarting;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 74a030a6389a..6a2a96076809 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -114,10 +114,10 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
-import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RESIZE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_INSETS;
import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
@@ -3985,7 +3985,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* Called when the insets state changed.
*/
void notifyInsetsChanged() {
- ProtoLog.d(WM_DEBUG_IME, "notifyInsetsChanged for %s ", this);
+ ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "notifyInsetsChanged for %s ", this);
try {
mClient.insetsChanged(getCompatInsetsState(),
hasMoved(),
@@ -3997,7 +3997,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
public void notifyInsetsControlChanged() {
- ProtoLog.d(WM_DEBUG_IME, "notifyInsetsControlChanged for %s ", this);
+ ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "notifyInsetsControlChanged for %s ", this);
if (mAppDied || mRemoved) {
return;
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 46adb32ff103..fe3a77e87f65 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -440,7 +440,6 @@ public final class SystemServer implements Dumpable {
private static final String SYSPROP_START_UPTIME = "sys.system_server.start_uptime";
private Future<?> mZygotePreload;
- private Future<?> mBlobStoreServiceStart;
private final SystemServerDumper mDumper = new SystemServerDumper();
@@ -2262,12 +2261,9 @@ public final class SystemServer implements Dumpable {
t.traceEnd();
}
- mBlobStoreServiceStart = SystemServerInitThreadPool.submit(() -> {
- final TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog();
- traceLog.traceBegin(START_BLOB_STORE_SERVICE);
- mSystemServiceManager.startService(BLOB_STORE_MANAGER_SERVICE_CLASS);
- traceLog.traceEnd();
- }, START_BLOB_STORE_SERVICE);
+ t.traceBegin(START_BLOB_STORE_SERVICE);
+ mSystemServiceManager.startService(BLOB_STORE_MANAGER_SERVICE_CLASS);
+ t.traceEnd();
// Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
t.traceBegin("StartDreamManager");
@@ -2673,9 +2669,6 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startService(APP_COMPAT_OVERRIDES_SERVICE_CLASS);
t.traceEnd();
- ConcurrentUtils.waitForFutureNoInterrupt(mBlobStoreServiceStart,
- START_BLOB_STORE_SERVICE);
-
// These are needed to propagate to the runnable below.
final NetworkManagementService networkManagementF = networkManagement;
final NetworkStatsService networkStatsF = networkStats;
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 3c97c95ab340..9d89f1263ab0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -103,7 +103,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
val dataAppDirectory: File =
File(Files.createTempDirectory("data").toFile(), "app")
val frameworkSignature: SigningDetails = SigningDetails(arrayOf(generateSpySignature()), 3)
- val systemPartitions: List<PackageManagerService.ScanPartition> =
+ val systemPartitions: List<ScanPartition> =
redirectScanPartitions(PackageManagerService.SYSTEM_PARTITIONS)
val session: StaticMockitoSession
@@ -476,7 +476,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
}
/** Finds the appropriate partition, if available, based on a scan flag unique to it. */
- fun getPartitionFromFlag(scanFlagMask: Int): PackageManagerService.ScanPartition =
+ fun getPartitionFromFlag(scanFlagMask: Int): ScanPartition =
systemPartitions.first { (it.scanFlag and scanFlagMask) != 0 }
@Throws(Exception::class)
@@ -630,11 +630,11 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
/** Override get*Folder methods to point to temporary local directories */
@Throws(IOException::class)
- private fun redirectScanPartitions(partitions: List<PackageManagerService.ScanPartition>):
- List<PackageManagerService.ScanPartition> {
- val spiedPartitions: MutableList<PackageManagerService.ScanPartition> =
+ private fun redirectScanPartitions(partitions: List<ScanPartition>):
+ List<ScanPartition> {
+ val spiedPartitions: MutableList<ScanPartition> =
ArrayList(partitions.size)
- for (partition: PackageManagerService.ScanPartition in partitions) {
+ for (partition: ScanPartition in partitions) {
val spy = spy(partition)
val newRoot = Files.createTempDirectory(partition.folder.name).toFile()
whenever(spy.overlayFolder).thenReturn(File(newRoot, "overlay"))
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackagesBroadcastTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackagesBroadcastTest.kt
index 7a6110bdbda3..f17fa625d007 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackagesBroadcastTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackagesBroadcastTest.kt
@@ -79,8 +79,8 @@ class SuspendPackagesBroadcastTest {
mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
mockAllowList(packageSetting2, allowList(10001, 10002, 10003))
- pms.sendPackagesSuspendedForUser(
- packagesToSuspend, uidsToSuspend, TEST_USER_ID, /* suspended = */ true)
+ pms.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
+ packagesToSuspend, uidsToSuspend, TEST_USER_ID)
verify(pms).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
anyInt(), nullable(), nullable(), any(), nullable(), any(), nullable())
@@ -97,8 +97,8 @@ class SuspendPackagesBroadcastTest {
mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
mockAllowList(packageSetting2, allowList(10001, 10002, 10007))
- pms.sendPackagesSuspendedForUser(
- packagesToSuspend, uidsToSuspend, TEST_USER_ID, /* suspended = */ true)
+ pms.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
+ packagesToSuspend, uidsToSuspend, TEST_USER_ID)
verify(pms, times(2)).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
anyInt(), nullable(), nullable(), any(), nullable(), any(), nullable())
@@ -118,8 +118,8 @@ class SuspendPackagesBroadcastTest {
mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
mockAllowList(packageSetting2, null)
- pms.sendPackagesSuspendedForUser(
- packagesToSuspend, uidsToSuspend, TEST_USER_ID, /* suspended = */ true)
+ pms.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
+ packagesToSuspend, uidsToSuspend, TEST_USER_ID)
verify(pms, times(2)).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
anyInt(), nullable(), nullable(), any(), nullable(), nullable(), nullable())
@@ -133,6 +133,22 @@ class SuspendPackagesBroadcastTest {
}
}
+ @Test
+ @Throws(Exception::class)
+ fun sendPackagesSuspendModifiedForUser() {
+ pms.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
+ packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+ verify(pms).sendPackageBroadcast(
+ eq(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED), nullable(), bundleCaptor.capture(),
+ anyInt(), nullable(), nullable(), any(), nullable(), nullable(), nullable())
+
+ var modifiedPackages = bundleCaptor.value.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST)
+ var modifiedUids = bundleCaptor.value.getIntArray(Intent.EXTRA_CHANGED_UID_LIST)
+ assertThat(modifiedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2)
+ assertThat(modifiedUids).asList().containsExactly(
+ packageSetting1.appId, packageSetting2.appId)
+ }
+
private fun allowList(vararg uids: Int) = SparseArray<IntArray>().apply {
this.put(TEST_USER_ID, uids)
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/OWNERS b/services/tests/mockingservicestests/src/com/android/server/tare/OWNERS
new file mode 100644
index 000000000000..217a5edff08b
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/OWNERS
@@ -0,0 +1 @@
+include /apex/jobscheduler/service/java/com/android/server/tare/OWNERS \ No newline at end of file
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index c19155f51743..11e1230df7c1 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -144,7 +144,6 @@ java_library {
"utils/**/*.java",
"utils/**/*.kt",
"utils-mockito/**/*.kt",
- ":services.core-sources-deviceconfig-interface",
],
static_libs: [
"junit",
@@ -161,7 +160,6 @@ java_library {
"utils/**/*.java",
"utils/**/*.kt",
"utils-mockito/**/*.kt",
- ":services.core-sources-deviceconfig-interface",
],
static_libs: [
"junit",
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index f241fe1b86bd..dbed4457b3dd 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -151,7 +151,7 @@ public class PackageManagerServiceTest {
String[] partitions = { "system", "vendor", "odm", "oem", "product", "system_ext" };
String[] appdir = { "app", "priv-app" };
for (int i = 0; i < partitions.length; i++) {
- final PackageManagerService.ScanPartition scanPartition =
+ final ScanPartition scanPartition =
PackageManagerService.SYSTEM_PARTITIONS.get(i);
for (int j = 0; j < appdir.length; j++) {
File path = new File(String.format("%s/%s/A.apk", partitions[i], appdir[j]));
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index 6c6cfd45c6c5..77b9fd30f71b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -87,6 +87,8 @@ public class ScanTests {
PlatformCompat mMockCompatibility;
@Mock
PackageManagerService.Injector mMockInjector;
+ @Mock
+ PackageManagerService mMockPackageManager;
@Before
public void setupInjector() {
@@ -432,7 +434,7 @@ public class ScanTests {
final ParsingPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
.addUsesPermission(new ParsedUsesPermission(Manifest.permission.FACTORY_TEST, 0));
- final ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
+ final ScanResult scanResult = mMockPackageManager.scanPackageOnlyLI(
createBasicScanRequestBuilder(basicPackage).build(),
mMockInjector,
true /*isUnderFactoryTest*/,
@@ -480,7 +482,7 @@ public class ScanTests {
private ScanResult executeScan(
ScanRequest scanRequest) throws PackageManagerException {
- ScanResult result = PackageManagerService.scanPackageOnlyLI(
+ ScanResult result = mMockPackageManager.scanPackageOnlyLI(
scanRequest,
mMockInjector,
false /*isUnderFactoryTest*/,
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 8f9eb22f0d01..2c5159aef1e2 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -35,7 +35,6 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
@@ -1016,7 +1015,7 @@ public class VibratorManagerServiceTest {
assertEquals(IExternalVibratorService.SCALE_NONE, firstScale);
assertEquals(IExternalVibratorService.SCALE_NONE, secondScale);
verify(firstController).mute();
- verifyNoMoreInteractions(secondController);
+ verify(secondController, never()).mute();
// Set external control called only once.
assertEquals(Arrays.asList(true), mVibratorProviders.get(1).getExternalControlStates());
}
diff --git a/services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java b/services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java
index a67f64596ef5..161232161b91 100644
--- a/services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java
+++ b/services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java
@@ -18,13 +18,14 @@ package com.android.server.testutils;
import android.annotation.NonNull;
import android.provider.DeviceConfig;
+import android.provider.DeviceConfigInterface;
import android.util.ArrayMap;
import android.util.Pair;
import com.android.internal.util.Preconditions;
-import com.android.server.utils.DeviceConfigInterface;
import java.lang.reflect.Constructor;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
@@ -33,10 +34,17 @@ import java.util.concurrent.TimeUnit;
public class FakeDeviceConfigInterface implements DeviceConfigInterface {
+ private static final String COMPOSITE_DELIMITER = "/";
private Map<String, String> mProperties = new HashMap<>();
private ArrayMap<DeviceConfig.OnPropertiesChangedListener, Pair<String, Executor>> mListeners =
new ArrayMap<>();
+ private static String createCompositeName(@NonNull String namespace, @NonNull String name) {
+ Preconditions.checkNotNull(namespace);
+ Preconditions.checkNotNull(name);
+ return namespace + COMPOSITE_DELIMITER + name;
+ }
+
public void clearProperties() {
mProperties.clear();
}
@@ -91,6 +99,59 @@ public class FakeDeviceConfigInterface implements DeviceConfigInterface {
}
@Override
+ public DeviceConfig.Properties getProperties(String namespace, String... names) {
+ if (!mProperties.keySet().contains(namespace)) {
+ return new DeviceConfig.Properties(namespace, null);
+ }
+ DeviceConfig.Properties.Builder propertiesBuilder = new DeviceConfig.Properties.Builder(
+ namespace);
+
+ for (String compositeName : mProperties.keySet()) {
+ if (compositeName.split(COMPOSITE_DELIMITER).length != 2) {
+ continue;
+ }
+
+ String existingPropertyNamespace = compositeName.split(COMPOSITE_DELIMITER)[0];
+ String existingPropertyName = compositeName.split(COMPOSITE_DELIMITER)[1];
+
+ if ((names.length == 0 && existingPropertyNamespace.equals(namespace)) || Arrays.asList(
+ names).contains(compositeName)) {
+ propertiesBuilder.setString(existingPropertyName, mProperties.get(compositeName));
+ }
+ }
+
+ return propertiesBuilder.build();
+ }
+
+ @Override
+ public boolean setProperty(String namespace, String name, String value, boolean makeDefault) {
+ putPropertyAndNotify(namespace, name, value);
+ return true;
+ }
+
+ @Override
+ public boolean setProperties(DeviceConfig.Properties properties)
+ throws DeviceConfig.BadConfigException {
+ for (String property : properties.getKeyset()) {
+ String compositeName = createCompositeName(properties.getNamespace(), property);
+ putPropertyAndNotify(properties.getNamespace(), compositeName,
+ properties.getString(property, ""));
+ }
+ return true;
+ }
+
+ @Override
+ public boolean deleteProperty(String namespace, String name) {
+ mProperties.remove(createCompositeName(namespace, name));
+ return true;
+ }
+
+ @Override
+ public void resetToDefaults(int resetMode, String namespace) {
+ clearProperties();
+ }
+
+ @Override
public String getString(String namespace, String name, String defaultValue) {
String value = getProperty(namespace, name);
return value != null ? value : defaultValue;
@@ -166,10 +227,4 @@ public class FakeDeviceConfigInterface implements DeviceConfigInterface {
DeviceConfig.OnPropertiesChangedListener listener) {
mListeners.remove(listener);
}
-
- private static String createCompositeName(@NonNull String namespace, @NonNull String name) {
- Preconditions.checkNotNull(namespace);
- Preconditions.checkNotNull(name);
- return namespace + "/" + name;
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
index 26a68821a672..a34586bb2e8a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
@@ -30,6 +30,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -40,8 +41,10 @@ import static org.mockito.Mockito.timeout;
import android.app.WaitResult;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.ConditionVariable;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
@@ -190,6 +193,24 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase {
verify(taskChangeNotifier, never()).notifyActivityDismissingDockedRootTask();
}
+ /** Ensures that the calling package name passed to client complies with package visibility. */
+ @Test
+ public void testFilteredReferred() {
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setLaunchedFromPackage("other.package").setCreateTask(true).build();
+ assertNotNull(activity.launchedFromPackage);
+ try {
+ mSupervisor.realStartActivityLocked(activity, activity.app, false /* andResume */,
+ false /* checkConfig */);
+ } catch (RemoteException ignored) {
+ }
+ verify(activity).getFilteredReferrer(eq(activity.launchedFromPackage));
+
+ activity.deliverNewIntentLocked(ActivityBuilder.DEFAULT_FAKE_UID,
+ new Intent(), null /* intentGrants */, "other.package2");
+ verify(activity).getFilteredReferrer(eq("other.package2"));
+ }
+
/**
* Ensures that notify focus task changes.
*/
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index a165e1cf7ad3..53bae4156d6b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -26,15 +26,19 @@ import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.verify;
import android.os.Binder;
import android.os.IBinder;
@@ -47,6 +51,8 @@ import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationTarget;
import android.view.WindowManager;
+import android.window.ITaskFragmentOrganizer;
+import android.window.TaskFragmentOrganizer;
import androidx.test.filters.SmallTest;
@@ -737,4 +743,38 @@ public class AppTransitionControllerTest extends WindowTestsBase {
mAppTransitionController.getRemoteAnimationOverride(
activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
}
+
+ @Test
+ public void testGetRemoteAnimationOverrideTaskFragmentOrganizer() {
+ // TaskFragmentOrganizer registers remote animation.
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final ITaskFragmentOrganizer iOrganizer =
+ ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder());
+ final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter);
+ mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer);
+ mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition);
+
+ // Create a TaskFragment with embedded activity.
+ final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(createTask(mDisplayContent))
+ .createActivityCount(1)
+ .setOrganizer(organizer)
+ .build();
+ final ActivityRecord activity = taskFragment.getTopMostActivity();
+ activity.allDrawn = true;
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare a transition for TaskFragment.
+ mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0);
+ mDisplayContent.mOpeningApps.add(activity);
+ mDisplayContent.mChangingContainers.add(taskFragment);
+ mDisplayContent.mAppTransitionController.handleAppTransitionReady();
+
+ // Check if the transition has been overridden.
+ verify(mDisplayContent.mAppTransition)
+ .overridePendingAppTransitionRemote(adapter, false /* sync */);
+ }
} \ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 5c79f5ca2c66..98c1eabe4eca 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -21,6 +21,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.testing.Assert.assertThrows;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -36,6 +37,7 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.view.RemoteAnimationDefinition;
import android.view.SurfaceControl;
import android.window.ITaskFragmentOrganizer;
import android.window.TaskFragmentCreationParams;
@@ -70,6 +72,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
private IBinder mFragmentToken;
private WindowContainerTransaction mTransaction;
private WindowContainerToken mFragmentWindowToken;
+ private RemoteAnimationDefinition mDefinition;
@Before
public void setup() {
@@ -83,6 +86,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
new TaskFragment(mAtm, mFragmentToken, true /* createdByOrganizer */);
mTransaction = new WindowContainerTransaction();
mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
+ mDefinition = new RemoteAnimationDefinition();
spyOn(mController);
spyOn(mOrganizer);
@@ -208,6 +212,18 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
}
@Test
+ public void testRegisterRemoteAnimations() {
+ mController.registerOrganizer(mIOrganizer);
+ mController.registerRemoteAnimations(mIOrganizer, mDefinition);
+
+ assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer));
+
+ mController.unregisterRemoteAnimations(mIOrganizer);
+
+ assertNull(mController.getRemoteAnimationDefinition(mIOrganizer));
+ }
+
+ @Test
public void testWindowContainerTransaction_setTaskFragmentOrganizer() {
mOrganizer.applyTransaction(mTransaction);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index e7ef6ae7cc0a..454ecd7e9d85 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -67,6 +67,7 @@ import static org.mockito.Mockito.mock;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
@@ -100,6 +101,7 @@ import android.view.WindowManager;
import android.view.WindowManager.DisplayImePolicy;
import android.window.ITransitionPlayer;
import android.window.StartingWindowInfo;
+import android.window.TaskFragmentOrganizer;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
@@ -878,6 +880,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
private int mConfigChanges;
private int mLaunchedFromPid;
private int mLaunchedFromUid;
+ private String mLaunchedFromPackage;
private WindowProcessController mWpc;
private Bundle mIntentExtras;
private boolean mOnTop = false;
@@ -988,6 +991,11 @@ class WindowTestsBase extends SystemServiceTestsBase {
return this;
}
+ ActivityBuilder setLaunchedFromPackage(String packageName) {
+ mLaunchedFromPackage = packageName;
+ return this;
+ }
+
ActivityBuilder setUseProcess(WindowProcessController wpc) {
mWpc = wpc;
return this;
@@ -1077,6 +1085,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
final ActivityRecord activity = new ActivityRecord.Builder(mService)
.setLaunchedFromPid(mLaunchedFromPid)
.setLaunchedFromUid(mLaunchedFromUid)
+ .setLaunchedFromPackage(mLaunchedFromPackage)
.setIntent(intent)
.setActivityInfo(aInfo)
.setActivityOptions(options)
@@ -1128,6 +1137,8 @@ class WindowTestsBase extends SystemServiceTestsBase {
private boolean mCreateParentTask;
private boolean mCreateEmbeddedTask;
private int mCreateActivityCount = 0;
+ @Nullable
+ private TaskFragmentOrganizer mOrganizer;
TaskFragmentBuilder(ActivityTaskManagerService service) {
mAtm = service;
@@ -1154,11 +1165,16 @@ class WindowTestsBase extends SystemServiceTestsBase {
return this;
}
+ TaskFragmentBuilder setOrganizer(@Nullable TaskFragmentOrganizer organizer) {
+ mOrganizer = organizer;
+ return this;
+ }
+
TaskFragment build() {
SystemServicesTestRule.checkHoldsLock(mAtm.mGlobalLock);
final TaskFragment taskFragment = new TaskFragment(mAtm, null /* fragmentToken */,
- false /* createdByOrganizer */);
+ mOrganizer != null);
if (mParentTask == null && mCreateParentTask) {
mParentTask = new TaskBuilder(mAtm.mTaskSupervisor).build();
}
@@ -1176,6 +1192,10 @@ class WindowTestsBase extends SystemServiceTestsBase {
taskFragment.addChild(activity);
mCreateActivityCount--;
}
+ if (mOrganizer != null) {
+ taskFragment.setTaskFragmentOrganizer(
+ mOrganizer.getOrganizerToken(), 10000 /* pid */);
+ }
return taskFragment;
}
}
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 02bd0010de99..bc0a14667307 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -23,6 +23,8 @@ import android.os.Build;
import android.os.Bundle;
import android.util.ArrayMap;
+import com.android.internal.annotations.GuardedBy;
+
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -115,6 +117,7 @@ public final class Phone {
public static final int SDK_VERSION_R = 30;
// A Map allows us to track each Call by its Telecom-specified call ID
+ @GuardedBy("mLock")
private final Map<String, Call> mCallByTelecomCallId = new ArrayMap<>();
// A List allows us to keep the Calls in a stable iteration order so that casually developed
@@ -154,7 +157,7 @@ public final class Phone {
return;
}
- Call call = mCallByTelecomCallId.get(parcelableCall.getId());
+ Call call = getCallById(parcelableCall.getId());
if (call == null) {
call = new Call(this, parcelableCall.getId(), mInCallAdapter,
parcelableCall.getState(), mCallingPackage, mTargetSdkVersion);
@@ -191,14 +194,14 @@ public final class Phone {
if (mTargetSdkVersion < SDK_VERSION_R
&& parcelableCall.getState() == Call.STATE_AUDIO_PROCESSING) {
Log.i(this, "removing audio processing call during update for sdk compatibility");
- Call call = mCallByTelecomCallId.get(parcelableCall.getId());
+ Call call = getCallById(parcelableCall.getId());
if (call != null) {
internalRemoveCall(call);
}
return;
}
- Call call = mCallByTelecomCallId.get(parcelableCall.getId());
+ Call call = getCallById(parcelableCall.getId());
if (call != null) {
checkCallTree(parcelableCall);
call.internalUpdate(parcelableCall, mCallByTelecomCallId);
@@ -215,8 +218,14 @@ public final class Phone {
}
}
+ Call getCallById(String callId) {
+ synchronized (mLock) {
+ return mCallByTelecomCallId.get(callId);
+ }
+ }
+
final void internalSetPostDialWait(String telecomId, String remaining) {
- Call call = mCallByTelecomCallId.get(telecomId);
+ Call call = getCallById(telecomId);
if (call != null) {
call.internalSetPostDialWait(remaining);
}
@@ -230,7 +239,7 @@ public final class Phone {
}
final Call internalGetCallByTelecomId(String telecomId) {
- return mCallByTelecomCallId.get(telecomId);
+ return getCallById(telecomId);
}
final void internalBringToForeground(boolean showDialpad) {
@@ -249,35 +258,35 @@ public final class Phone {
}
final void internalOnConnectionEvent(String telecomId, String event, Bundle extras) {
- Call call = mCallByTelecomCallId.get(telecomId);
+ Call call = getCallById(telecomId);
if (call != null) {
call.internalOnConnectionEvent(event, extras);
}
}
final void internalOnRttUpgradeRequest(String callId, int requestId) {
- Call call = mCallByTelecomCallId.get(callId);
+ Call call = getCallById(callId);
if (call != null) {
call.internalOnRttUpgradeRequest(requestId);
}
}
final void internalOnRttInitiationFailure(String callId, int reason) {
- Call call = mCallByTelecomCallId.get(callId);
+ Call call = getCallById(callId);
if (call != null) {
call.internalOnRttInitiationFailure(reason);
}
}
final void internalOnHandoverFailed(String callId, int error) {
- Call call = mCallByTelecomCallId.get(callId);
+ Call call = getCallById(callId);
if (call != null) {
call.internalOnHandoverFailed(error);
}
}
final void internalOnHandoverComplete(String callId) {
- Call call = mCallByTelecomCallId.get(callId);
+ Call call = getCallById(callId);
if (call != null) {
call.internalOnHandoverComplete();
}
diff --git a/tools/aapt/Android.bp b/tools/aapt/Android.bp
index a19d183d617b..01eb4f69f842 100644
--- a/tools/aapt/Android.bp
+++ b/tools/aapt/Android.bp
@@ -50,7 +50,6 @@ cc_defaults {
"libbase",
"libz",
],
- group_static_libs: true,
cflags: [
"-Wall",
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 12dc156f75be..740b44e0ce28 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -72,7 +72,6 @@ cc_defaults {
"libidmap2_policies",
],
stl: "libc++_static",
- group_static_libs: true,
}
// ==========================================================
diff --git a/tools/aosp/aosp_sha.sh b/tools/aosp/aosp_sha.sh
index 3cdb27c74d63..ac23c3d9cb4a 100755
--- a/tools/aosp/aosp_sha.sh
+++ b/tools/aosp/aosp_sha.sh
@@ -35,6 +35,7 @@ else
echo
echo "If your change contains no confidential details (such as security fixes), please"
echo "upload and merge this change at https://android-review.googlesource.com/."
+ echo "Else add a tag 'Ignore-AOSP-First:' with the reason to bypass AOSP."
echo
exit 1
fi
diff --git a/tools/split-select/Android.bp b/tools/split-select/Android.bp
index c12fc6a7f253..540265793de6 100644
--- a/tools/split-select/Android.bp
+++ b/tools/split-select/Android.bp
@@ -48,7 +48,6 @@ cc_defaults {
"libbase",
"libz",
],
- group_static_libs: true,
target: {
windows: {