diff options
author | Dianne Hackborn <hackbod@google.com> | 2011-02-25 16:15:27 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-02-25 16:15:27 -0800 |
commit | d752c3b3e6c576ed1f18e86a7b18c33dc7c65791 (patch) | |
tree | 904a8f1e186aba26518269e3bf3271d765e31897 | |
parent | 53c7b1d544f1b78cc4fb206c74dc52b39b58b258 (diff) | |
parent | e7f972122db87dc54e41ed1a6e417534d43bca3a (diff) | |
download | frameworks_base-d752c3b3e6c576ed1f18e86a7b18c33dc7c65791.zip frameworks_base-d752c3b3e6c576ed1f18e86a7b18c33dc7c65791.tar.gz frameworks_base-d752c3b3e6c576ed1f18e86a7b18c33dc7c65791.tar.bz2 |
Merge "Implement issue #3426299: Introduce application "stopped" state"
-rw-r--r-- | api/current.xml | 55 | ||||
-rw-r--r-- | core/java/android/content/Intent.java | 42 | ||||
-rw-r--r-- | core/java/android/content/pm/ApplicationInfo.java | 6 | ||||
-rw-r--r-- | core/java/android/content/pm/IPackageManager.aidl | 6 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageParser.java | 13 | ||||
-rw-r--r-- | core/java/android/server/BluetoothInputProfileHandler.java | 1 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 2 | ||||
-rw-r--r-- | services/java/com/android/server/IntentResolver.java | 19 | ||||
-rw-r--r-- | services/java/com/android/server/PackageManagerService.java | 342 | ||||
-rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 74 | ||||
-rw-r--r-- | services/java/com/android/server/am/ActivityStack.java | 8 |
11 files changed, 531 insertions, 37 deletions
diff --git a/api/current.xml b/api/current.xml index 07d04ca..872e627 100644 --- a/api/current.xml +++ b/api/current.xml @@ -53230,6 +53230,17 @@ visibility="public" > </field> +<field name="ACTION_MY_PACKAGE_REPLACED" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.intent.action.MY_PACKAGE_REPLACED"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="ACTION_NEW_OUTGOING_CALL" type="java.lang.String" transient="false" @@ -53274,6 +53285,17 @@ visibility="public" > </field> +<field name="ACTION_PACKAGE_FIRST_LAUNCH" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.intent.action.PACKAGE_FIRST_LAUNCH"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="ACTION_PACKAGE_INSTALL" type="java.lang.String" transient="false" @@ -54549,6 +54571,17 @@ visibility="public" > </field> +<field name="FLAG_EXCLUDE_STOPPED_PACKAGES" + type="int" + transient="false" + volatile="false" + value="16" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="FLAG_FROM_BACKGROUND" type="int" transient="false" @@ -54582,6 +54615,17 @@ visibility="public" > </field> +<field name="FLAG_INCLUDE_STOPPED_PACKAGES" + type="int" + transient="false" + volatile="false" + value="32" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="FLAG_RECEIVER_REGISTERED_ONLY" type="int" transient="false" @@ -58397,6 +58441,17 @@ visibility="public" > </field> +<field name="FLAG_STOPPED" + type="int" + transient="false" + volatile="false" + value="2097152" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="FLAG_SUPPORTS_LARGE_SCREENS" type="int" transient="false" diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index ce7f096..7bdd1b9 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1312,6 +1312,17 @@ public class Intent implements Parcelable, Cloneable { @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED"; /** + * Broadcast Action: A new version of your application has been installed + * over an existing one. This is only sent to the application that was + * replaced. It does not contain any additional data; to receive it, just + * use an intent filter for this action. + * + * <p class="note">This is a protected intent that can only be sent + * by the system. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_MY_PACKAGE_REPLACED = "android.intent.action.MY_PACKAGE_REPLACED"; + /** * Broadcast Action: An existing application package has been removed from * the device. The data contains the name of the package. The package * that is being installed does <em>not</em> receive this Intent. @@ -1403,6 +1414,17 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_UID_REMOVED = "android.intent.action.UID_REMOVED"; /** + * Broadcast Action: Sent to the installer package of an application + * when that application is first launched (that is the first time it + * is moved out of the stopped state). The data contains the name of the package. + * + * <p class="note">This is a protected intent that can only be sent + * by the system. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_PACKAGE_FIRST_LAUNCH = "android.intent.action.PACKAGE_FIRST_LAUNCH"; + + /** * Broadcast Action: Resources for a set of packages (which were * previously unavailable) are currently * available since the media on which they exist is available. @@ -2442,6 +2464,20 @@ public class Intent implements Parcelable, Cloneable { * been found to create the final resolved list. */ public static final int FLAG_DEBUG_LOG_RESOLUTION = 0x00000008; + /** + * If set, this intent will not match any components in packages that + * are currently stopped. If this is not set, then the default behavior + * is to include such applications in the result. + */ + public static final int FLAG_EXCLUDE_STOPPED_PACKAGES = 0x00000010; + /** + * If set, this intent will always match any components in packages that + * are currently stopped. This is the default behavior when + * {@link #FLAG_EXCLUDE_STOPPED_PACKAGES} is not set. If both of these + * flags are set, this one wins (it allows overriding of exclude for + * places where the framework may automatically set the exclude flag). + */ + public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 0x00000020; /** * If set, the new activity is not kept in the history stack. As soon as @@ -3915,6 +3951,12 @@ public class Intent implements Parcelable, Cloneable { return mFlags; } + /** @hide */ + public boolean isExcludingStopped() { + return (mFlags&(FLAG_EXCLUDE_STOPPED_PACKAGES|FLAG_INCLUDE_STOPPED_PACKAGES)) + == FLAG_EXCLUDE_STOPPED_PACKAGES; + } + /** * Retrieve the application package name this Intent is limited to. When * resolving an Intent, if non-null this limits the resolution to only diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 2d95781..92b2c3b 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -278,6 +278,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int FLAG_LARGE_HEAP = 1<<20; /** + * Value for {@link #flags}: true if this application's package is in + * the stopped state. + */ + public static final int FLAG_STOPPED = 1<<21; + + /** * Value for {@link #flags}: Set to true if the application has been * installed using the forward lock option. * diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 034525e..fbf8f92 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -210,6 +210,12 @@ interface IPackageManager { int getApplicationEnabledSetting(in String packageName); /** + * Set whether the given package should be considered stopped, making + * it not visible to implicit intents that filter out stopped packages. + */ + void setPackageStoppedState(String packageName, boolean stopped); + + /** * Free storage by deleting LRU sorted list of cache files across * all applications. If the currently available free storage * on the device is greater than or equal to the requested diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 7676258..7ebfda4 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -2817,6 +2817,9 @@ public class PackageParser { // User set enabled state. public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; + // Whether the package has been stopped. + public boolean mSetStopped = false; + // Additional data supplied by callers. public Object mExtras; @@ -3071,6 +3074,11 @@ public class PackageParser { if (!sCompatibilityModeEnabled) { p.applicationInfo.disableCompatibilityMode(); } + if (p.mSetStopped) { + p.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED; + } else { + p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED; + } return p.applicationInfo; } @@ -3085,6 +3093,11 @@ public class PackageParser { if (!sCompatibilityModeEnabled) { ai.disableCompatibilityMode(); } + if (p.mSetStopped) { + p.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED; + } else { + p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED; + } if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { ai.enabled = true; } else if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) { diff --git a/core/java/android/server/BluetoothInputProfileHandler.java b/core/java/android/server/BluetoothInputProfileHandler.java index cdc0f2d..e6513fd 100644 --- a/core/java/android/server/BluetoothInputProfileHandler.java +++ b/core/java/android/server/BluetoothInputProfileHandler.java @@ -187,6 +187,7 @@ final class BluetoothInputProfileHandler { intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.putExtra(BluetoothInputDevice.EXTRA_PREVIOUS_STATE, prevState); intent.putExtra(BluetoothInputDevice.EXTRA_STATE, state); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM); debugLog("InputDevice state : device: " + device + " State:" + prevState + "->" + state); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 12d7afd..beb824c 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -35,10 +35,12 @@ <protected-broadcast android:name="android.intent.action.PACKAGE_INSTALL" /> <protected-broadcast android:name="android.intent.action.PACKAGE_ADDED" /> <protected-broadcast android:name="android.intent.action.PACKAGE_REPLACED" /> + <protected-broadcast android:name="android.intent.action.MY_PACKAGE_REPLACED" /> <protected-broadcast android:name="android.intent.action.PACKAGE_REMOVED" /> <protected-broadcast android:name="android.intent.action.PACKAGE_CHANGED" /> <protected-broadcast android:name="android.intent.action.PACKAGE_RESTARTED" /> <protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" /> + <protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" /> <protected-broadcast android:name="android.intent.action.UID_REMOVED" /> <protected-broadcast android:name="android.intent.action.CONFIGURATION_CHANGED" /> <protected-broadcast android:name="android.intent.action.LOCALE_CHANGED" /> diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java index e9ee12c..b78389b 100644 --- a/services/java/com/android/server/IntentResolver.java +++ b/services/java/com/android/server/IntentResolver.java @@ -36,7 +36,6 @@ import android.util.LogPrinter; import android.util.Printer; import android.util.Config; -import android.content.ContentResolver; import android.content.Intent; import android.content.IntentFilter; @@ -326,6 +325,15 @@ public class IntentResolver<F extends IntentFilter, R extends Object> { return true; } + /** + * Returns whether the object associated with the given filter is + * "stopped," that is whether it should not be included in the result + * if the intent requests to excluded stopped objects. + */ + protected boolean isFilterStopped(F filter) { + return false; + } + protected String packageForFilter(F filter) { return null; } @@ -496,6 +504,8 @@ public class IntentResolver<F extends IntentFilter, R extends Object> { final String action = intent.getAction(); final Uri data = intent.getData(); + final boolean excludingStopped = intent.isExcludingStopped(); + final int N = src != null ? src.size() : 0; boolean hasNonDefaults = false; int i; @@ -504,6 +514,13 @@ public class IntentResolver<F extends IntentFilter, R extends Object> { int match; if (debug) Slog.v(TAG, "Matching against filter " + filter); + if (excludingStopped && isFilterStopped(filter)) { + if (debug) { + Slog.v(TAG, " Filter's target is stopped; skipping"); + } + continue; + } + // Do we already have this one? if (!allowFilterResult(filter, dest)) { if (debug) { diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 7af60c5..f1a6e15 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -85,7 +85,6 @@ import android.os.Process; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; -import android.provider.Settings; import android.security.SystemKeyStore; import android.util.*; import android.view.Display; @@ -114,12 +113,10 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.zip.ZipEntry; -import java.util.zip.ZipException; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; @@ -140,6 +137,7 @@ class PackageManagerService extends IPackageManager.Stub { private static final boolean DEBUG_PREFERRED = false; private static final boolean DEBUG_UPGRADE = false; private static final boolean DEBUG_INSTALL = false; + private static final boolean DEBUG_STOPPED = false; private static final boolean MULTIPLE_APPLICATION_UIDS = true; private static final int RADIO_UID = Process.PHONE_UID; @@ -153,8 +151,6 @@ class PackageManagerService extends IPackageManager.Stub { private static final boolean GET_CERTIFICATES = true; - private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled"; - private static final int REMOVE_EVENTS = FileObserver.CLOSE_WRITE | FileObserver.DELETE | FileObserver.MOVED_FROM; private static final int ADD_EVENTS = @@ -360,6 +356,7 @@ class PackageManagerService extends IPackageManager.Stub { static final int MCS_GIVE_UP = 11; static final int UPDATED_MEDIA_STATUS = 12; static final int WRITE_SETTINGS = 13; + static final int WRITE_STOPPED_PACKAGES = 14; static final int WRITE_SETTINGS_DELAY = 10*1000; // 10 seconds @@ -603,11 +600,14 @@ class PackageManagerService extends IPackageManager.Stub { } sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, res.pkg.applicationInfo.packageName, - extras, null); + extras, null, null); if (update) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, res.pkg.applicationInfo.packageName, - extras, null); + extras, null, null); + sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, + null, null, + res.pkg.applicationInfo.packageName, null); } if (res.removedInfo.args != null) { // Remove the replaced package's older resources safely now @@ -661,10 +661,19 @@ class PackageManagerService extends IPackageManager.Stub { Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mPackages) { removeMessages(WRITE_SETTINGS); + removeMessages(WRITE_STOPPED_PACKAGES); mSettings.writeLP(); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } break; + case WRITE_STOPPED_PACKAGES: { + Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); + synchronized (mPackages) { + removeMessages(WRITE_STOPPED_PACKAGES); + mSettings.writeStoppedLP(); + } + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + } break; } } } @@ -675,6 +684,12 @@ class PackageManagerService extends IPackageManager.Stub { } } + void scheduleWriteStoppedPackagesLocked() { + if (!mHandler.hasMessages(WRITE_STOPPED_PACKAGES)) { + mHandler.sendEmptyMessageDelayed(WRITE_STOPPED_PACKAGES, WRITE_SETTINGS_DELAY); + } + } + static boolean installOnSd(int flags) { if (((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) || ((flags & PackageManager.INSTALL_INTERNAL) != 0)) { @@ -1489,6 +1504,7 @@ class PackageManagerService extends IPackageManager.Stub { ps.pkg.applicationInfo.dataDir = getDataPathForPackage(ps.pkg).getPath(); ps.pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString; ps.pkg.mSetEnabled = ps.enabled; + ps.pkg.mSetStopped = ps.stopped; } return generatePackageInfo(ps.pkg, flags); } @@ -4096,6 +4112,18 @@ class PackageManagerService extends IPackageManager.Stub { } @Override + protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter) { + PackageParser.Package p = filter.activity.owner; + if (p != null) { + PackageSetting ps = (PackageSetting)p.mExtras; + if (ps != null) { + return ps.stopped; + } + } + return false; + } + + @Override protected String packageForFilter(PackageParser.ActivityIntentInfo info) { return info.activity.owner.packageName; } @@ -4253,6 +4281,18 @@ class PackageManagerService extends IPackageManager.Stub { } @Override + protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter) { + PackageParser.Package p = filter.service.owner; + if (p != null) { + PackageSetting ps = (PackageSetting)p.mExtras; + if (ps != null) { + return ps.stopped; + } + } + return false; + } + + @Override protected String packageForFilter(PackageParser.ServiceIntentInfo info) { return info.service.owner.packageName; } @@ -4355,7 +4395,7 @@ class PackageManagerService extends IPackageManager.Stub { }; private static final void sendPackageBroadcast(String action, String pkg, - Bundle extras, IIntentReceiver finishedReceiver) { + Bundle extras, String targetPkg, IIntentReceiver finishedReceiver) { IActivityManager am = ActivityManagerNative.getDefault(); if (am != null) { try { @@ -4364,6 +4404,9 @@ class PackageManagerService extends IPackageManager.Stub { if (extras != null) { intent.putExtras(extras); } + if (targetPkg != null) { + intent.setPackage(targetPkg); + } intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); am.broadcastIntent(null, intent, null, finishedReceiver, 0, null, null, null, finishedReceiver != null, false); @@ -4499,13 +4542,13 @@ class PackageManagerService extends IPackageManager.Stub { extras.putInt(Intent.EXTRA_UID, removedUid); extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false); sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, - extras, null); + extras, null, null); } if (addedPackage != null) { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, addedUid); sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, - extras, null); + extras, null, null); } } @@ -6218,8 +6261,12 @@ class PackageManagerService extends IPackageManager.Stub { extras.putInt(Intent.EXTRA_UID, info.removedUid >= 0 ? info.removedUid : info.uid); extras.putBoolean(Intent.EXTRA_REPLACING, true); - sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras, null); - sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras, null); + sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, + extras, null, null); + sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, + extras, null, null); + sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, + null, packageName, null); } } // Force a gc here. @@ -6250,10 +6297,11 @@ class PackageManagerService extends IPackageManager.Stub { extras.putBoolean(Intent.EXTRA_REPLACING, true); } if (removedPackage != null) { - sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras, null); + sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, + extras, null, null); } if (removedUid >= 0) { - sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null); + sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null); } } } @@ -6950,7 +6998,45 @@ class PackageManagerService extends IPackageManager.Stub { extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList); extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag); extras.putInt(Intent.EXTRA_UID, packageUid); - sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, null); + sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, null, null); + } + + public void setPackageStoppedState(String packageName, boolean stopped) { + PackageSetting pkgSetting; + final int uid = Binder.getCallingUid(); + final int permission = mContext.checkCallingOrSelfPermission( + android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); + final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); + synchronized (mPackages) { + pkgSetting = mSettings.mPackages.get(packageName); + if (pkgSetting == null) { + throw new IllegalArgumentException("Unknown package: " + packageName); + } + if (!allowedByPermission && (uid != pkgSetting.userId)) { + throw new SecurityException( + "Permission Denial: attempt to change stopped state from pid=" + + Binder.getCallingPid() + + ", uid=" + uid + ", package uid=" + pkgSetting.userId); + } + if (DEBUG_STOPPED && stopped) { + RuntimeException e = new RuntimeException("here"); + e.fillInStackTrace(); + Slog.i(TAG, "Stopping package " + packageName, e); + } + if (pkgSetting.stopped != stopped) { + pkgSetting.stopped = stopped; + pkgSetting.pkg.mSetStopped = stopped; + if (pkgSetting.notLaunched) { + if (pkgSetting.installerPackageName != null) { + sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, + pkgSetting.installerPackageName, null, + pkgSetting.name, null); + } + pkgSetting.notLaunched = false; + } + scheduleWriteStoppedPackagesLocked(); + } + } } public String getInstallerPackageName(String packageName) { @@ -7300,11 +7386,15 @@ class PackageManagerService extends IPackageManager.Stub { date.setTime(ps.firstInstallTime); pw.println(sdf.format(date)); pw.print(" lastUpdateTime="); date.setTime(ps.lastUpdateTime); pw.println(sdf.format(date)); + if (ps.installerPackageName != null) { + pw.print(" installerPackageName="); pw.println(ps.installerPackageName); + } pw.print(" signatures="); pw.println(ps.signatures); pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed); pw.print(" haveGids="); pw.println(ps.haveGids); pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags)); pw.print(" installStatus="); pw.print(ps.installStatus); + pw.print(" stopped="); pw.print(ps.stopped); pw.print(" enabled="); pw.println(ps.enabled); if (ps.disabledComponents.size() > 0) { pw.println(" disabledComponents:"); @@ -7841,6 +7931,13 @@ class PackageManagerService extends IPackageManager.Stub { boolean permissionsFixed; boolean haveGids; + // Whether this package is currently stopped, thus can not be + // started until explicitly launched by the user. + public boolean stopped; + + // Set to true if we have never launched this app. + public boolean notLaunched; + /* Explicitly disabled components */ HashSet<String> disabledComponents = new HashSet<String>(0); /* Explicitly enabled components */ @@ -7885,6 +7982,8 @@ class PackageManagerService extends IPackageManager.Stub { permissionsFixed = base.permissionsFixed; haveGids = base.haveGids; + stopped = base.stopped; + notLaunched = base.notLaunched; disabledComponents = (HashSet<String>) base.disabledComponents.clone(); @@ -7941,6 +8040,8 @@ class PackageManagerService extends IPackageManager.Stub { signatures = base.signatures; permissionsFixed = base.permissionsFixed; haveGids = base.haveGids; + stopped = base.stopped; + notLaunched = base.notLaunched; disabledComponents = base.disabledComponents; enabledComponents = base.enabledComponents; enabled = base.enabled; @@ -8039,6 +8140,8 @@ class PackageManagerService extends IPackageManager.Stub { private final File mSettingsFilename; private final File mBackupSettingsFilename; private final File mPackageListFilename; + private final File mStoppedPackagesFilename; + private final File mBackupStoppedPackagesFilename; private final HashMap<String, PackageSetting> mPackages = new HashMap<String, PackageSetting>(); // List of replaced system applications @@ -8138,6 +8241,8 @@ class PackageManagerService extends IPackageManager.Stub { mSettingsFilename = new File(systemDir, "packages.xml"); mBackupSettingsFilename = new File(systemDir, "packages-backup.xml"); mPackageListFilename = new File(systemDir, "packages.list"); + mStoppedPackagesFilename = new File(systemDir, "packages-stopped.xml"); + mBackupStoppedPackagesFilename = new File(systemDir, "packages-stopped-backup.xml"); } PackageSetting getPackageLP(PackageParser.Package pkg, PackageSetting origPackage, @@ -8393,6 +8498,16 @@ class PackageManagerService extends IPackageManager.Stub { nativeLibraryPathString, vc, pkgFlags); p.setTimeStamp(codePath.lastModified()); p.sharedUser = sharedUser; + // If this is not a system app, it starts out stopped. + if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { + if (DEBUG_STOPPED) { + RuntimeException e = new RuntimeException("here"); + e.fillInStackTrace(); + Slog.i(TAG, "Stopping package " + name, e); + } + p.stopped = true; + p.notLaunched = true; + } if (sharedUser != null) { p.userId = sharedUser.userId; } else if (MULTIPLE_APPLICATION_UIDS) { @@ -8439,6 +8554,7 @@ class PackageManagerService extends IPackageManager.Stub { private void insertPackageSettingLP(PackageSetting p, PackageParser.Package pkg) { p.pkg = pkg; pkg.mSetEnabled = p.enabled; + pkg.mSetStopped = p.stopped; final String codePath = pkg.applicationInfo.sourceDir; final String resourcePath = pkg.applicationInfo.publicSourceDir; // Update code path if needed @@ -8655,6 +8771,180 @@ class PackageManagerService extends IPackageManager.Stub { } } + void writeStoppedLP() { + // Keep the old stopped packages around until we know the new ones have + // been successfully written. + if (mStoppedPackagesFilename.exists()) { + // Presence of backup settings file indicates that we failed + // to persist packages earlier. So preserve the older + // backup for future reference since the current packages + // might have been corrupted. + if (!mBackupStoppedPackagesFilename.exists()) { + if (!mStoppedPackagesFilename.renameTo(mBackupStoppedPackagesFilename)) { + Log.wtf(TAG, "Unable to backup package manager stopped packages, " + + "current changes will be lost at reboot"); + return; + } + } else { + mStoppedPackagesFilename.delete(); + Slog.w(TAG, "Preserving older stopped packages backup"); + } + } + + try { + FileOutputStream fstr = new FileOutputStream(mStoppedPackagesFilename); + BufferedOutputStream str = new BufferedOutputStream(fstr); + + //XmlSerializer serializer = XmlUtils.serializerInstance(); + XmlSerializer serializer = new FastXmlSerializer(); + serializer.setOutput(str, "utf-8"); + serializer.startDocument(null, true); + serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); + + serializer.startTag(null, "stopped-packages"); + + for (PackageSetting pkg : mPackages.values()) { + if (pkg.stopped) { + serializer.startTag(null, "pkg"); + serializer.attribute(null, "name", pkg.name); + if (pkg.notLaunched) { + serializer.attribute(null, "nl", "1"); + } + serializer.endTag(null, "pkg"); + } + } + + serializer.endTag(null, "stopped-packages"); + + serializer.endDocument(); + + str.flush(); + FileUtils.sync(fstr); + str.close(); + + // New settings successfully written, old ones are no longer + // needed. + mBackupStoppedPackagesFilename.delete(); + FileUtils.setPermissions(mStoppedPackagesFilename.toString(), + FileUtils.S_IRUSR|FileUtils.S_IWUSR + |FileUtils.S_IRGRP|FileUtils.S_IWGRP + |FileUtils.S_IROTH, + -1, -1); + + // Done, all is good! + return; + + } catch(java.io.IOException e) { + Log.wtf(TAG, "Unable to write package manager stopped packages, " + + " current changes will be lost at reboot", e); + } + + // Clean up partially written files + if (mStoppedPackagesFilename.exists()) { + if (!mStoppedPackagesFilename.delete()) { + Log.i(TAG, "Failed to clean up mangled file: " + mStoppedPackagesFilename); + } + } + } + + // Note: assumed "stopped" field is already cleared in all packages. + void readStoppedLP() { + FileInputStream str = null; + if (mBackupStoppedPackagesFilename.exists()) { + try { + str = new FileInputStream(mBackupStoppedPackagesFilename); + mReadMessages.append("Reading from backup stopped packages file\n"); + reportSettingsProblem(Log.INFO, "Need to read from backup stopped packages file"); + if (mSettingsFilename.exists()) { + // If both the backup and normal file exist, we + // ignore the normal one since it might have been + // corrupted. + Slog.w(TAG, "Cleaning up stopped packages file " + + mStoppedPackagesFilename); + mStoppedPackagesFilename.delete(); + } + } catch (java.io.IOException e) { + // We'll try for the normal settings file. + } + } + + try { + if (str == null) { + if (!mStoppedPackagesFilename.exists()) { + mReadMessages.append("No stopped packages file found\n"); + reportSettingsProblem(Log.INFO, "No stopped packages file file; " + + "assuming all started"); + // At first boot, make sure no packages are stopped. + // We usually want to have third party apps initialize + // in the stopped state, but not at first boot. + for (PackageSetting pkg : mPackages.values()) { + pkg.stopped = false; + pkg.notLaunched = false; + } + return; + } + str = new FileInputStream(mStoppedPackagesFilename); + } + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(str, null); + + int type; + while ((type=parser.next()) != XmlPullParser.START_TAG + && type != XmlPullParser.END_DOCUMENT) { + ; + } + + if (type != XmlPullParser.START_TAG) { + mReadMessages.append("No start tag found in stopped packages file\n"); + reportSettingsProblem(Log.WARN, + "No start tag found in package manager stopped packages"); + return; + } + + int outerDepth = parser.getDepth(); + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG + || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("pkg")) { + String name = parser.getAttributeValue(null, "name"); + PackageSetting ps = mPackages.get(name); + if (ps != null) { + ps.stopped = true; + if ("1".equals(parser.getAttributeValue(null, "nl"))) { + ps.notLaunched = true; + } + } else { + Slog.w(TAG, "No package known for stopped package: " + name); + } + XmlUtils.skipCurrentTag(parser); + } else { + Slog.w(TAG, "Unknown element under <stopped-packages>: " + + parser.getName()); + XmlUtils.skipCurrentTag(parser); + } + } + + str.close(); + + } catch(XmlPullParserException e) { + mReadMessages.append("Error reading: " + e.toString()); + reportSettingsProblem(Log.ERROR, "Error reading stopped packages: " + e); + Log.wtf(TAG, "Error reading package manager stopped packages", e); + + } catch(java.io.IOException e) { + mReadMessages.append("Error reading: " + e.toString()); + reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); + Log.wtf(TAG, "Error reading package manager stopped packages", e); + + } + } + void writeLP() { //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024); @@ -8667,7 +8957,8 @@ class PackageManagerService extends IPackageManager.Stub { // might have been corrupted. if (!mBackupSettingsFilename.exists()) { if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) { - Slog.w(TAG, "Unable to backup package manager settings, current changes will be lost at reboot"); + Log.wtf(TAG, "Unable to backup package manager settings, " + + " current changes will be lost at reboot"); return; } } else { @@ -8829,17 +9120,21 @@ class PackageManagerService extends IPackageManager.Stub { |FileUtils.S_IROTH, -1, -1); + writeStoppedLP(); + return; } catch(XmlPullParserException e) { - Slog.w(TAG, "Unable to write package manager settings, current changes will be lost at reboot", e); + Log.wtf(TAG, "Unable to write package manager settings, " + + "current changes will be lost at reboot", e); } catch(java.io.IOException e) { - Slog.w(TAG, "Unable to write package manager settings, current changes will be lost at reboot", e); + Log.wtf(TAG, "Unable to write package manager settings, " + + "current changes will be lost at reboot", e); } // Clean up partially written files if (mSettingsFilename.exists()) { if (!mSettingsFilename.delete()) { - Log.i(TAG, "Failed to clean up mangled file: " + mSettingsFilename); + Log.wtf(TAG, "Failed to clean up mangled file: " + mSettingsFilename); } } //Debug.stopMethodTracing(); @@ -9063,6 +9358,7 @@ class PackageManagerService extends IPackageManager.Stub { if (type != XmlPullParser.START_TAG) { mReadMessages.append("No start tag found in settings file\n"); reportSettingsProblem(Log.WARN, "No start tag found in package manager settings"); + Log.wtf(TAG, "No start tag found in package manager settings"); return false; } @@ -9126,12 +9422,12 @@ class PackageManagerService extends IPackageManager.Stub { } catch(XmlPullParserException e) { mReadMessages.append("Error reading: " + e.toString()); reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); - Slog.e(TAG, "Error reading package manager settings", e); + Log.wtf(TAG, "Error reading package manager settings", e); } catch(java.io.IOException e) { mReadMessages.append("Error reading: " + e.toString()); reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); - Slog.e(TAG, "Error reading package manager settings", e); + Log.wtf(TAG, "Error reading package manager settings", e); } @@ -9165,6 +9461,8 @@ class PackageManagerService extends IPackageManager.Stub { } mPendingPackages.clear(); + readStoppedLP(); + mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, " + mSharedUsers.size() + " shared uids\n"); @@ -9970,7 +10268,7 @@ class PackageManagerService extends IPackageManager.Stub { } String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE; - sendPackageBroadcast(action, null, extras, finishedReceiver); + sendPackageBroadcast(action, null, extras, null, finishedReceiver); } } 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 @@ public final class ActivityManagerService extends ActivityManagerNative return; } forceStopPackageLocked(packageName, pkgUid); + try { + pm.setPackageStoppedState(packageName, true); + } catch (RemoteException e) { + } } } finally { Binder.restoreCallingIdentity(callingId); @@ -5544,20 +5548,31 @@ public final class ActivityManagerService extends ActivityManagerNative // 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; - } - cpr.launchingApp = proc; - mLaunchingProviders.add(cpr); - Binder.restoreCallingIdentity(origId); + + 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); + } } // Make sure the provider is published (the same provider class @@ -5814,6 +5829,13 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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); diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 5b44d39..3a613bb 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -1293,6 +1293,14 @@ public class ActivityStack { } } + // Launching this app's activity, make sure the app is no longer + // considered stopped. + try { + AppGlobals.getPackageManager().setPackageStoppedState( + next.packageName, false); + } catch (RemoteException e1) { + } + // We are starting up the next activity, so tell the window manager // that the previous one will be hidden soon. This way it can know // to ignore it when computing the desired screen orientation. |