summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server
diff options
context:
space:
mode:
authorChristopher Tate <ctate@google.com>2013-11-13 17:42:28 -0800
committerChristopher Tate <ctate@google.com>2013-11-14 12:37:31 -0800
commitba629da331d01d74067afdda5d4255682d4b24d7 (patch)
tree9c1044d486111af341585ca377e0877880e6aa88 /services/java/com/android/server
parenta951fa56f1855cd0337bddacc01e35868c6d66d6 (diff)
downloadframeworks_base-ba629da331d01d74067afdda5d4255682d4b24d7.zip
frameworks_base-ba629da331d01d74067afdda5d4255682d4b24d7.tar.gz
frameworks_base-ba629da331d01d74067afdda5d4255682d4b24d7.tar.bz2
Ensure recipient can be launched before attempting broadcast delivery
User removal or eviction inherently races with broadcast delivery. This patch introduces a latest-possible recheck of the availbility of the target application before attempting to send it a broadcast. Once the process has actually been spun up the system is essentially committed to presenting it as a running application, and there is no later check of the availability of the app: the failure mode for continuing to attempt delivery is a crash *in the app process*, and is user-visible. We now check the app+userid existence of the intended recipient just prior to committing to launch its process for receipt, and if it is no longer available we simply skip that receiver and continue normally. Bug 11652784 Bug 11272019 Bug 8263020 Change-Id: Ib19ba2af493250890db7371c1a9f853772db1af0
Diffstat (limited to 'services/java/com/android/server')
-rw-r--r--services/java/com/android/server/am/BroadcastQueue.java21
-rwxr-xr-xservices/java/com/android/server/pm/PackageManagerService.java18
2 files changed, 39 insertions, 0 deletions
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index dd3d8aa..bfb667f 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -27,6 +27,7 @@ import android.content.ComponentName;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
@@ -814,6 +815,26 @@ public final class BroadcastQueue {
+ " to " + r.curApp + ": process crashing");
skip = true;
}
+ if (!skip) {
+ boolean isAvailable = false;
+ try {
+ isAvailable = AppGlobals.getPackageManager().isPackageAvailable(
+ info.activityInfo.packageName,
+ UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
+ } catch (Exception e) {
+ // all such failures mean we skip this receiver
+ Slog.w(TAG, "Exception getting recipient info for "
+ + info.activityInfo.packageName, e);
+ }
+ if (!isAvailable) {
+ if (DEBUG_BROADCAST) {
+ Slog.v(TAG, "Skipping delivery to " + info.activityInfo.packageName
+ + " / " + info.activityInfo.applicationInfo.uid
+ + " : package no longer available");
+ }
+ skip = true;
+ }
+ }
if (skip) {
if (DEBUG_BROADCAST) Slog.v(TAG,
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 7ae9251..24f8ed8 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1771,6 +1771,24 @@ public class PackageManagerService extends IPackageManager.Stub {
state, userId);
}
+ public boolean isPackageAvailable(String packageName, int userId) {
+ if (!sUserManager.exists(userId)) return false;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "is package available");
+ synchronized (mPackages) {
+ PackageParser.Package p = mPackages.get(packageName);
+ if (p != null) {
+ final PackageSetting ps = (PackageSetting) p.mExtras;
+ if (ps != null) {
+ final PackageUserState state = ps.readUserState(userId);
+ if (state != null) {
+ return PackageParser.isAvailable(state);
+ }
+ }
+ }
+ }
+ return false;
+ }
+
@Override
public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;