Broadcast PACKAGE_CHANGED in response to OVERLAY_CHANGED
Consolidate what triggers a package change: teach the package manager to
broadcast PACKAGE_CHANGED in response to the overlay manager
broadcasting OVERLAY_CHANGED. Since the overlay manager listens for
PACKAGE_CHANGED, the package manager will include a new extra in the
intent to act as a secret handshake between the managers that the
overlay manager should ignore the intent in order to prevent an endless
loop.
Bug: 140790688
Test: manual (adb shell cmd overlay enable ... && adb shell dumpsys activity broadcasts # check "Historical broadcasts")
Change-Id: I430efcce5adf0dca03058cd6ff694541f0ac3ef5
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 9e7b4648..5f3e503 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -17,11 +17,13 @@
package com.android.server.om;
import static android.app.AppGlobals.getPackageManager;
+import static android.content.Intent.ACTION_OVERLAY_CHANGED;
import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_CHANGED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
+import static android.content.Intent.EXTRA_REASON;
import static android.content.pm.PackageManager.SIGNATURE_MATCH;
import static android.os.Trace.TRACE_TAG_RRO;
import static android.os.Trace.traceBegin;
@@ -356,7 +358,11 @@
}
break;
case ACTION_PACKAGE_CHANGED:
- onPackageChanged(packageName, userIds);
+ // ignore the intent if it was sent by the package manager as a result of the
+ // overlay manager having sent ACTION_OVERLAY_CHANGED
+ if (!ACTION_OVERLAY_CHANGED.equals(intent.getStringExtra(EXTRA_REASON))) {
+ onPackageChanged(packageName, userIds);
+ }
break;
case ACTION_PACKAGE_REMOVED:
if (replacing) {
@@ -885,7 +891,7 @@
FgThread.getHandler().post(() -> {
updateAssets(userId, targetPackageName);
- final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED,
+ final Intent intent = new Intent(ACTION_OVERLAY_CHANGED,
Uri.fromParts("package", targetPackageName, null));
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b1d05f4..2d3be69 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1675,7 +1675,8 @@
}
// Send broadcasts
for (int i = 0; i < size; i++) {
- sendPackageChangedBroadcast(packages[i], true, components[i], uids[i]);
+ sendPackageChangedBroadcast(packages[i], true, components[i], uids[i],
+ null);
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
break;
@@ -2163,7 +2164,7 @@
// send broadcast that all consumers of the static shared library have changed
sendPackageChangedBroadcast(pkg.packageName, false /*killFlag*/,
new ArrayList<>(Collections.singletonList(pkg.packageName)),
- pkg.applicationInfo.uid);
+ pkg.applicationInfo.uid, null);
}
}
@@ -20039,7 +20040,7 @@
if (sendNow) {
int packageUid = UserHandle.getUid(userId, pkgSetting.appId);
sendPackageChangedBroadcast(packageName,
- (flags&PackageManager.DONT_KILL_APP) != 0, components, packageUid);
+ (flags & PackageManager.DONT_KILL_APP) != 0, components, packageUid, null);
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -20071,7 +20072,8 @@
}
private void sendPackageChangedBroadcast(String packageName,
- boolean killFlag, ArrayList<String> componentNames, int packageUid) {
+ boolean killFlag, ArrayList<String> componentNames, int packageUid,
+ String reason) {
if (DEBUG_INSTALL)
Log.v(TAG, "Sending package changed: package=" + packageName + " components="
+ componentNames);
@@ -20082,6 +20084,9 @@
extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList);
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
extras.putInt(Intent.EXTRA_UID, packageUid);
+ if (reason != null) {
+ extras.putString(Intent.EXTRA_REASON, reason);
+ }
// If this is not reporting a change of the overall package, then only send it
// to registered receivers. We don't want to launch a swath of apps for every
// little component state change.
@@ -20329,6 +20334,34 @@
}, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
}
+ IntentFilter overlayFilter = new IntentFilter(Intent.ACTION_OVERLAY_CHANGED);
+ overlayFilter.addDataScheme("package");
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent == null) {
+ return;
+ }
+ Uri data = intent.getData();
+ if (data == null) {
+ return;
+ }
+ String packageName = data.getSchemeSpecificPart();
+ if (packageName == null) {
+ return;
+ }
+ PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ return;
+ }
+ sendPackageChangedBroadcast(pkg.packageName,
+ false /* killFlag */,
+ new ArrayList<>(Collections.singletonList(pkg.packageName)),
+ pkg.applicationInfo.uid,
+ Intent.ACTION_OVERLAY_CHANGED);
+ }
+ }, overlayFilter);
+
mModuleInfoProvider.systemReady();
// Installer service might attempt to install some packages that have been staged for