diff options
author | Christopher Tate <ctate@google.com> | 2013-11-13 17:42:28 -0800 |
---|---|---|
committer | Christopher Tate <ctate@google.com> | 2013-11-14 12:37:31 -0800 |
commit | ba629da331d01d74067afdda5d4255682d4b24d7 (patch) | |
tree | 9c1044d486111af341585ca377e0877880e6aa88 /services/java/com | |
parent | a951fa56f1855cd0337bddacc01e35868c6d66d6 (diff) | |
download | frameworks_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')
-rw-r--r-- | services/java/com/android/server/am/BroadcastQueue.java | 21 | ||||
-rwxr-xr-x | services/java/com/android/server/pm/PackageManagerService.java | 18 |
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; |