Implement issue #3426299: Introduce application "stopped" state
The package manager now keeps track of whether an application is
stopped. There are new intent flags to control whether intent
filters in a stopped application will match the intent. This is
currently used in one place, sending broadcasts, so that stopped
apps can not be launched due to background processes.
The package manager during first init makes sure no applications
are in the stopped state. When new applications are installed,
that begin in the stopped state. When the activity manager is
launching a component of an application, it ensures the application
is taken out of the stopped state.
The "force stop" button in manage applications will now put an
application back in to the stopped state; it can't go back out
of the stopped state until one of its components is launched by
the activity manager.
There will probably be a few more places where we need to filter
stopped applications out of intent matches, but doing this for
broadcast is a very big first step.
This also introduces a new broadcast that is sent to an application
after it is replaced with a new .apk. But only if the app is not
in the stopped state. This makes it a lot easier for developers to
implement code to get their application back in proper running shape
after an upgrade.
Finally another new broadcast is added that is sent to a package's
installer at the first time it is launched. This allows the installer
to tell the package about it being installed only when it is first
actually used.
Change-Id: I589c53ff0e0ece868fe734ace4439c0d202dca2d
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 399c19a..8d30868 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3145,6 +3145,10 @@
return;
}
forceStopPackageLocked(packageName, pkgUid);
+ try {
+ pm.setPackageStoppedState(packageName, true);
+ } catch (RemoteException e) {
+ }
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -5544,20 +5548,31 @@
// started.
if (i >= N) {
final long origId = Binder.clearCallingIdentity();
- ProcessRecord proc = startProcessLocked(cpi.processName,
- cpr.appInfo, false, 0, "content provider",
- new ComponentName(cpi.applicationInfo.packageName,
- cpi.name), false);
- if (proc == null) {
- Slog.w(TAG, "Unable to launch app "
- + cpi.applicationInfo.packageName + "/"
- + cpi.applicationInfo.uid + " for provider "
- + name + ": process is bad");
- return null;
+
+ try {
+ // Content provider is now in use, its package can't be stopped.
+ try {
+ AppGlobals.getPackageManager().setPackageStoppedState(
+ cpr.appInfo.packageName, false);
+ } catch (RemoteException e) {
+ }
+
+ ProcessRecord proc = startProcessLocked(cpi.processName,
+ cpr.appInfo, false, 0, "content provider",
+ new ComponentName(cpi.applicationInfo.packageName,
+ cpi.name), false);
+ if (proc == null) {
+ Slog.w(TAG, "Unable to launch app "
+ + cpi.applicationInfo.packageName + "/"
+ + cpi.applicationInfo.uid + " for provider "
+ + name + ": process is bad");
+ return null;
+ }
+ cpr.launchingApp = proc;
+ mLaunchingProviders.add(cpr);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- cpr.launchingApp = proc;
- mLaunchingProviders.add(cpr);
- Binder.restoreCallingIdentity(origId);
}
// Make sure the provider is published (the same provider class
@@ -5814,6 +5829,13 @@
updateLruProcessLocked(app, true, true);
}
+ // This package really, really can not be stopped.
+ try {
+ AppGlobals.getPackageManager().setPackageStoppedState(
+ info.packageName, false);
+ } catch (RemoteException e) {
+ }
+
if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
== (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
app.persistent = true;
@@ -9354,6 +9376,13 @@
// restarting state.
mRestartingServices.remove(r);
+ // Service is now being launched, its package can't be stopped.
+ try {
+ AppGlobals.getPackageManager().setPackageStoppedState(
+ r.packageName, false);
+ } catch (RemoteException e) {
+ }
+
final String appName = r.processName;
ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
if (app != null && app.thread != null) {
@@ -10248,6 +10277,13 @@
ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
}
+ // Backup agent is now in use, its package can't be stopped.
+ try {
+ AppGlobals.getPackageManager().setPackageStoppedState(
+ app.packageName, false);
+ } catch (RemoteException e) {
+ }
+
BackupRecord r = new BackupRecord(ss, app, backupMode);
ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
// startProcessLocked() returns existing proc's record if it's already running
@@ -10535,6 +10571,9 @@
boolean ordered, boolean sticky, int callingPid, int callingUid) {
intent = new Intent(intent);
+ // By default broadcasts do not go to stopped apps.
+ intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
+
if (DEBUG_BROADCAST_LIGHT) Slog.v(
TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
+ " ordered=" + ordered);
@@ -11566,6 +11605,13 @@
info.activityInfo.name);
r.curReceiver = info.activityInfo;
+ // Broadcast is being executed, its package can't be stopped.
+ try {
+ AppGlobals.getPackageManager().setPackageStoppedState(
+ r.curComponent.getPackageName(), false);
+ } catch (RemoteException e) {
+ }
+
// Is this receiver's application already running?
ProcessRecord app = getProcessRecordLocked(targetProcess,
info.activityInfo.applicationInfo.uid);