diff options
31 files changed, 1176 insertions, 456 deletions
diff --git a/api/current.txt b/api/current.txt index d053109..bcb6fab 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6293,6 +6293,7 @@ package android.content.pm { field public static final int FLAG_EXTERNAL_STORAGE = 262144; // 0x40000 field public static final int FLAG_FACTORY_TEST = 16; // 0x10 field public static final int FLAG_HAS_CODE = 4; // 0x4 + field public static final int FLAG_INSTALLED = 8388608; // 0x800000 field public static final int FLAG_KILL_AFTER_RESTORE = 65536; // 0x10000 field public static final int FLAG_LARGE_HEAP = 1048576; // 0x100000 field public static final int FLAG_PERSISTENT = 8; // 0x8 @@ -6629,6 +6630,17 @@ package android.content.pm { field public java.lang.String packageName; } + public class PackageUserState { + ctor public PackageUserState(); + ctor public PackageUserState(android.content.pm.PackageUserState); + field public java.util.HashSet disabledComponents; + field public int enabled; + field public java.util.HashSet enabledComponents; + field public boolean installed; + field public boolean notLaunched; + field public boolean stopped; + } + public class PathPermission extends android.os.PatternMatcher { ctor public PathPermission(java.lang.String, int, java.lang.String, java.lang.String); ctor public PathPermission(android.os.Parcel); @@ -26928,6 +26940,7 @@ package android.webkit { method public synchronized int getDefaultFixedFontSize(); method public synchronized int getDefaultFontSize(); method public synchronized java.lang.String getDefaultTextEncodingName(); + method public static java.lang.String getDefaultUserAgent(android.content.Context); method public android.webkit.WebSettings.ZoomDensity getDefaultZoom(); method public boolean getDisplayZoomControls(); method public synchronized boolean getDomStorageEnabled(); @@ -26958,7 +26971,6 @@ package android.webkit { method public synchronized boolean getUseWideViewPort(); method public deprecated synchronized int getUserAgent(); method public synchronized java.lang.String getUserAgentString(); - method public static java.lang.String getDefaultUserAgent(android.content.Context); method public void setAllowContentAccess(boolean); method public void setAllowFileAccess(boolean); method public abstract void setAllowFileAccessFromFileURLs(boolean); diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index a79eb14..22fc1ad 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -393,7 +393,7 @@ public class Am { private void runStartService() throws Exception { Intent intent = makeIntent(); System.out.println("Starting service: " + intent); - ComponentName cn = mAm.startService(null, intent, intent.getType()); + ComponentName cn = mAm.startService(null, intent, intent.getType(), 0); if (cn == null) { System.err.println("Error: Not found; no service started."); } diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index b34fd05..32865a4 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -776,7 +776,7 @@ public final class Pm { } private void runInstall() { - int installFlags = 0; + int installFlags = PackageManager.INSTALL_ALL_USERS; String installerPackageName = null; String opt; @@ -811,6 +811,8 @@ public final class Pm { } else if (opt.equals("-f")) { // Override if -s option is specified. installFlags |= PackageManager.INSTALL_INTERNAL; + } else if (opt.equals("-d")) { + installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE; } else if (opt.equals("--algo")) { algo = nextOptionData(); if (algo == null) { @@ -1105,7 +1107,7 @@ public final class Pm { String opt = nextOption(); if (opt != null && opt.equals("-k")) { - unInstallFlags = PackageManager.DONT_DELETE_DATA; + unInstallFlags = PackageManager.DELETE_KEEP_DATA; } String pkg = nextArg(); @@ -1525,6 +1527,7 @@ public final class Pm { System.err.println(" -i: specify the installer package name."); System.err.println(" -s: install package on sdcard."); System.err.println(" -f: install package on internal flash."); + System.err.println(" -d: allow version code downgrade."); System.err.println(""); System.err.println("pm uninstall: removes a package from the system. Options:"); System.err.println(" -k: keep the data and cache directories around after package removal."); diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 3197a63..adc9434 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -697,7 +697,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM IApplicationThread app = ApplicationThreadNative.asInterface(b); Intent service = Intent.CREATOR.createFromParcel(data); String resolvedType = data.readString(); - ComponentName cn = startService(app, service, resolvedType); + int userId = data.readInt(); + ComponentName cn = startService(app, service, resolvedType, userId); reply.writeNoException(); ComponentName.writeToParcel(cn, reply); return true; @@ -709,7 +710,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM IApplicationThread app = ApplicationThreadNative.asInterface(b); Intent service = Intent.CREATOR.createFromParcel(data); String resolvedType = data.readString(); - int res = stopService(app, service, resolvedType); + int userId = data.readInt(); + int res = stopService(app, service, resolvedType, userId); reply.writeNoException(); reply.writeInt(res); return true; @@ -2523,7 +2525,7 @@ class ActivityManagerProxy implements IActivityManager } public ComponentName startService(IApplicationThread caller, Intent service, - String resolvedType) throws RemoteException + String resolvedType, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -2531,6 +2533,7 @@ class ActivityManagerProxy implements IActivityManager data.writeStrongBinder(caller != null ? caller.asBinder() : null); service.writeToParcel(data, 0); data.writeString(resolvedType); + data.writeInt(userId); mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0); reply.readException(); ComponentName res = ComponentName.readFromParcel(reply); @@ -2539,7 +2542,7 @@ class ActivityManagerProxy implements IActivityManager return res; } public int stopService(IApplicationThread caller, Intent service, - String resolvedType) throws RemoteException + String resolvedType, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -2547,6 +2550,7 @@ class ActivityManagerProxy implements IActivityManager data.writeStrongBinder(caller != null ? caller.asBinder() : null); service.writeToParcel(data, 0); data.writeString(resolvedType); + data.writeInt(userId); mRemote.transact(STOP_SERVICE_TRANSACTION, data, reply, 0); reply.readException(); int res = reply.readInt(); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index f3f75ce..0f10c4f 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -45,6 +45,7 @@ import android.content.pm.ManifestDigest; import android.content.pm.UserInfo; import android.content.pm.VerificationParams; import android.content.pm.VerifierDeviceIdentity; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; @@ -997,6 +998,21 @@ final class ApplicationPackageManager extends PackageManager { } @Override + public int installExistingPackage(String packageName) + throws NameNotFoundException { + try { + int res = mPM.installExistingPackage(packageName); + if (res == INSTALL_FAILED_INVALID_URI) { + throw new NameNotFoundException("Package " + packageName + " doesn't exist"); + } + return res; + } catch (RemoteException e) { + // Should never happen! + throw new NameNotFoundException("Package " + packageName + " doesn't exist"); + } + } + + @Override public void verifyPendingInstall(int id, int response) { try { mPM.verifyPendingInstall(id, response); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 0ae4d06..32086d7 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1220,11 +1220,21 @@ class ContextImpl extends Context { @Override public ComponentName startService(Intent service) { + return startServiceAsUser(service, Process.myUserHandle()); + } + + @Override + public boolean stopService(Intent service) { + return stopServiceAsUser(service, Process.myUserHandle()); + } + + @Override + public ComponentName startServiceAsUser(Intent service, UserHandle user) { try { service.setAllowFds(false); ComponentName cn = ActivityManagerNative.getDefault().startService( mMainThread.getApplicationThread(), service, - service.resolveTypeIfNeeded(getContentResolver())); + service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier()); if (cn != null && cn.getPackageName().equals("!")) { throw new SecurityException( "Not allowed to start service " + service @@ -1237,12 +1247,12 @@ class ContextImpl extends Context { } @Override - public boolean stopService(Intent service) { + public boolean stopServiceAsUser(Intent service, UserHandle user) { try { service.setAllowFds(false); int res = ActivityManagerNative.getDefault().stopService( mMainThread.getApplicationThread(), service, - service.resolveTypeIfNeeded(getContentResolver())); + service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier()); if (res < 0) { throw new SecurityException( "Not allowed to stop service " + service); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index a6d1995..c3e911e 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -133,9 +133,9 @@ public interface IActivityManager extends IInterface { public PendingIntent getRunningServiceControlPanel(ComponentName service) throws RemoteException; public ComponentName startService(IApplicationThread caller, Intent service, - String resolvedType) throws RemoteException; + String resolvedType, int userId) throws RemoteException; public int stopService(IApplicationThread caller, Intent service, - String resolvedType) throws RemoteException; + String resolvedType, int userId) throws RemoteException; public boolean stopServiceToken(ComponentName className, IBinder token, int startId) throws RemoteException; public void setServiceForeground(ComponentName className, IBinder token, diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 1460bf5..dc6d93f 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1414,6 +1414,16 @@ public abstract class Context { public abstract boolean stopService(Intent service); /** + * @hide like {@link #startService(Intent)} but for a specific user. + */ + public abstract ComponentName startServiceAsUser(Intent service, UserHandle user); + + /** + * @hide like {@link #stopService(Intent)} but for a specific user. + */ + public abstract boolean stopServiceAsUser(Intent service, UserHandle user); + + /** * Connect to an application service, creating it if needed. This defines * a dependency between your application and the service. The given * <var>conn</var> will receive the service object when it is created and be diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index 3a13725..4bbe44e 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -410,6 +410,18 @@ public class ContextWrapper extends Context { return mBase.stopService(name); } + /** @hide */ + @Override + public ComponentName startServiceAsUser(Intent service, UserHandle user) { + return mBase.startServiceAsUser(service, user); + } + + /** @hide */ + @Override + public boolean stopServiceAsUser(Intent name, UserHandle user) { + return mBase.stopServiceAsUser(name, user); + } + @Override public boolean bindService(Intent service, ServiceConnection conn, int flags) { diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index cbabc7c..1a82d58 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -302,6 +302,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int FLAG_SUPPORTS_RTL = 1<<22; /** + * Value for {@link #flags}: true if the application is currently + * installed for the calling user. + */ + public static final int FLAG_INSTALLED = 1<<23; + + /** * Value for {@link #flags}: Set to true if the application has been * installed using the forward lock option. * @@ -334,7 +340,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * {@link #FLAG_SUPPORTS_NORMAL_SCREENS}, * {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_SUPPORTS_XLARGE_SCREENS}, * {@link #FLAG_RESIZEABLE_FOR_SCREENS}, - * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE} + * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE}, + * {@link #FLAG_INSTALLED}. */ public int flags = 0; diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 0be8b83..0e1fe3e 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -32,6 +32,7 @@ import android.content.pm.IPackageStatsObserver; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.ManifestDigest; +import android.content.pm.PackageCleanItem; import android.content.pm.ParceledListSlice; import android.content.pm.ProviderInfo; import android.content.pm.PermissionGroupInfo; @@ -351,7 +352,7 @@ interface IPackageManager { */ void updateExternalMediaStatus(boolean mounted, boolean reportStatus); - String nextPackageToClean(String lastPackage); + PackageCleanItem nextPackageToClean(in PackageCleanItem lastPackage); void movePackage(String packageName, IPackageMoveObserver observer, int flags); @@ -369,6 +370,8 @@ interface IPackageManager { in VerificationParams verificationParams, in ContainerEncryptionParams encryptionParams); + int installExistingPackage(String packageName); + void verifyPendingInstall(int id, int verificationCode); void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay); diff --git a/core/java/android/content/pm/ManifestDigest.java b/core/java/android/content/pm/ManifestDigest.java index f5e72e0..75505bc 100644 --- a/core/java/android/content/pm/ManifestDigest.java +++ b/core/java/android/content/pm/ManifestDigest.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package android.content.pm; import android.os.Parcel; diff --git a/core/java/android/content/pm/PackageCleanItem.aidl b/core/java/android/content/pm/PackageCleanItem.aidl new file mode 100644 index 0000000..9bb203e --- /dev/null +++ b/core/java/android/content/pm/PackageCleanItem.aidl @@ -0,0 +1,18 @@ +/* Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.content.pm; + +parcelable PackageCleanItem; diff --git a/core/java/android/content/pm/PackageCleanItem.java b/core/java/android/content/pm/PackageCleanItem.java new file mode 100644 index 0000000..eea3b9c --- /dev/null +++ b/core/java/android/content/pm/PackageCleanItem.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm; + +import android.os.Parcel; +import android.os.Parcelable; + +/** @hide */ +public class PackageCleanItem { + public final String packageName; + public final boolean andCode; + + public PackageCleanItem(String packageName, boolean andCode) { + this.packageName = packageName; + this.andCode = andCode; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + try { + if (obj != null) { + PackageCleanItem other = (PackageCleanItem)obj; + return packageName.equals(other.packageName) && andCode == other.andCode; + } + } catch (ClassCastException e) { + } + return false; + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + packageName.hashCode(); + result = 31 * result + (andCode ? 1 : 0); + return result; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int parcelableFlags) { + dest.writeString(packageName); + dest.writeInt(andCode ? 1 : 0); + } + + public static final Parcelable.Creator<PackageCleanItem> CREATOR + = new Parcelable.Creator<PackageCleanItem>() { + public PackageCleanItem createFromParcel(Parcel source) { + return new PackageCleanItem(source); + } + + public PackageCleanItem[] newArray(int size) { + return new PackageCleanItem[size]; + } + }; + + private PackageCleanItem(Parcel source) { + packageName = source.readString(); + andCode = source.readInt() != 0; + } +} diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java index 9625944..a1566da 100644 --- a/core/java/android/content/pm/PackageInfoLite.java +++ b/core/java/android/content/pm/PackageInfoLite.java @@ -32,6 +32,11 @@ public class PackageInfoLite implements Parcelable { public String packageName; /** + * The android:versionCode of the package. + */ + public int versionCode; + + /** * Specifies the recommended install location. Can be one of * {@link #PackageHelper.RECOMMEND_INSTALL_INTERNAL} to install on internal storage * {@link #PackageHelper.RECOMMEND_INSTALL_EXTERNAL} to install on external media @@ -58,6 +63,7 @@ public class PackageInfoLite implements Parcelable { public void writeToParcel(Parcel dest, int parcelableFlags) { dest.writeString(packageName); + dest.writeInt(versionCode); dest.writeInt(recommendedInstallLocation); dest.writeInt(installLocation); @@ -82,6 +88,7 @@ public class PackageInfoLite implements Parcelable { private PackageInfoLite(Parcel source) { packageName = source.readString(); + versionCode = source.readInt(); recommendedInstallLocation = source.readInt(); installLocation = source.readInt(); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index b3e98e7..0d99d3f 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -310,6 +310,23 @@ public abstract class PackageManager { public static final int INSTALL_FROM_ADB = 0x00000020; /** + * Flag parameter for {@link #installPackage} to indicate that this install + * should immediately be visible to all users. + * + * @hide + */ + public static final int INSTALL_ALL_USERS = 0x00000040; + + /** + * Flag parameter for {@link #installPackage} to indicate that it is okay + * to install an update to an app where the newly installed app has a lower + * version code than the currently installed app. + * + * @hide + */ + public static final int INSTALL_ALLOW_DOWNGRADE = 0x00000080; + + /** * Flag parameter for * {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate * that you don't want to kill the app containing the component. Be careful when you set this @@ -529,6 +546,14 @@ public abstract class PackageManager { public static final int INSTALL_FAILED_UID_CHANGED = -24; /** + * Installation return code: this is passed to the {@link IPackageInstallObserver} by + * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if + * the new package has an older version code than the currently installed package. + * @hide + */ + public static final int INSTALL_FAILED_VERSION_DOWNGRADE = -25; + + /** * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} * if the parser was given a path that is not a file, or does not end with the expected @@ -625,7 +650,15 @@ public abstract class PackageManager { * * @hide */ - public static final int DONT_DELETE_DATA = 0x00000001; + public static final int DELETE_KEEP_DATA = 0x00000001; + + /** + * Flag parameter for {@link #deletePackage} to indicate that you want the + * package deleted for all users. + * + * @hide + */ + public static final int DELETE_ALL_USERS = 0x00000002; /** * Return code for when package deletion succeeds. This is passed to the @@ -2175,8 +2208,8 @@ public abstract class PackageManager { if ((flags & GET_SIGNATURES) != 0) { packageParser.collectCertificates(pkg, 0); } - return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, false, - COMPONENT_ENABLED_STATE_DEFAULT); + PackageUserState state = new PackageUserState(); + return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state); } /** @@ -2267,6 +2300,14 @@ public abstract class PackageManager { ContainerEncryptionParams encryptionParams); /** + * If there is already an application with the given package name installed + * on the system for other users, also install it for the calling user. + * @hide + */ + public abstract int installExistingPackage(String packageName) + throws NameNotFoundException; + + /** * Allows a package listening to the * {@link Intent#ACTION_PACKAGE_NEEDS_VERIFICATION package verification * broadcast} to respond to the package manager. The response must include @@ -2337,7 +2378,8 @@ public abstract class PackageManager { * @param observer An observer callback to get notified when the package deletion is * complete. {@link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be * called when that happens. observer may be null to indicate that no callback is desired. - * @param flags - possible values: {@link #DONT_DELETE_DATA} + * @param flags - possible values: {@link #DELETE_KEEP_DATA}, + * {@link #DELETE_ALL_USERS}. * * @hide */ diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index ac75040..237f5c5 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -203,11 +203,14 @@ public class PackageParser { */ public static class PackageLite { public final String packageName; + public final int versionCode; public final int installLocation; public final VerifierInfo[] verifiers; - public PackageLite(String packageName, int installLocation, List<VerifierInfo> verifiers) { + public PackageLite(String packageName, int versionCode, + int installLocation, List<VerifierInfo> verifiers) { this.packageName = packageName; + this.versionCode = versionCode; this.installLocation = installLocation; this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]); } @@ -243,14 +246,15 @@ public class PackageParser { return name.endsWith(".apk"); } + /* public static PackageInfo generatePackageInfo(PackageParser.Package p, int gids[], int flags, long firstInstallTime, long lastUpdateTime, HashSet<String> grantedPermissions) { - + PackageUserState state = new PackageUserState(); return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime, - grantedPermissions, false, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, - UserHandle.getCallingUserId()); + grantedPermissions, state, UserHandle.getCallingUserId()); } + */ /** * Generate and return the {@link PackageInfo} for a parsed package. @@ -260,23 +264,30 @@ public class PackageParser { */ public static PackageInfo generatePackageInfo(PackageParser.Package p, int gids[], int flags, long firstInstallTime, long lastUpdateTime, - HashSet<String> grantedPermissions, boolean stopped, int enabledState) { + HashSet<String> grantedPermissions, PackageUserState state) { return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime, - grantedPermissions, stopped, enabledState, UserHandle.getCallingUserId()); + grantedPermissions, state, UserHandle.getCallingUserId()); + } + + private static boolean checkUseInstalled(int flags, PackageUserState state) { + return state.installed || ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0); } public static PackageInfo generatePackageInfo(PackageParser.Package p, int gids[], int flags, long firstInstallTime, long lastUpdateTime, - HashSet<String> grantedPermissions, boolean stopped, int enabledState, int userId) { + HashSet<String> grantedPermissions, PackageUserState state, int userId) { + if (!checkUseInstalled(flags, state)) { + return null; + } PackageInfo pi = new PackageInfo(); pi.packageName = p.packageName; pi.versionCode = p.mVersionCode; pi.versionName = p.mVersionName; pi.sharedUserId = p.mSharedUserId; pi.sharedUserLabel = p.mSharedUserLabel; - pi.applicationInfo = generateApplicationInfo(p, flags, stopped, enabledState, userId); + pi.applicationInfo = generateApplicationInfo(p, flags, state, userId); pi.installLocation = p.installLocation; pi.firstInstallTime = firstInstallTime; pi.lastUpdateTime = lastUpdateTime; @@ -312,7 +323,7 @@ public class PackageParser { if (activity.info.enabled || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags, - stopped, enabledState, userId); + state, userId); } } } @@ -334,7 +345,7 @@ public class PackageParser { if (activity.info.enabled || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags, - stopped, enabledState, userId); + state, userId); } } } @@ -355,8 +366,8 @@ public class PackageParser { final Service service = p.services.get(i); if (service.info.enabled || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.services[j++] = generateServiceInfo(p.services.get(i), flags, stopped, - enabledState, userId); + pi.services[j++] = generateServiceInfo(p.services.get(i), flags, + state, userId); } } } @@ -377,8 +388,8 @@ public class PackageParser { final Provider provider = p.providers.get(i); if (provider.info.enabled || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags, stopped, - enabledState, userId); + pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags, + state, userId); } } } @@ -840,11 +851,19 @@ public class PackageParser { return null; } int installLocation = PARSE_DEFAULT_INSTALL_LOCATION; + int versionCode = 0; + int numFound = 0; for (int i = 0; i < attrs.getAttributeCount(); i++) { String attr = attrs.getAttributeName(i); if (attr.equals("installLocation")) { installLocation = attrs.getAttributeIntValue(i, PARSE_DEFAULT_INSTALL_LOCATION); + numFound++; + } else if (attr.equals("versionCode")) { + versionCode = attrs.getAttributeIntValue(i, 0); + numFound++; + } + if (numFound >= 2) { break; } } @@ -867,7 +886,7 @@ public class PackageParser { } } - return new PackageLite(pkgName.intern(), installLocation, verifiers); + return new PackageLite(pkgName.intern(), versionCode, installLocation, verifiers); } /** @@ -3458,13 +3477,25 @@ public class PackageParser { } } - private static boolean copyNeeded(int flags, Package p, int enabledState, Bundle metaData) { - if (enabledState != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { - boolean enabled = enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; + private static boolean copyNeeded(int flags, Package p, + PackageUserState state, Bundle metaData, int userId) { + if (userId != 0) { + // We always need to copy for other users, since we need + // to fix up the uid. + return true; + } + if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { + boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; if (p.applicationInfo.enabled != enabled) { return true; } } + if (!state.installed) { + return true; + } + if (state.stopped) { + return true; + } if ((flags & PackageManager.GET_META_DATA) != 0 && (metaData != null || p.mAppMetaData != null)) { return true; @@ -3476,32 +3507,34 @@ public class PackageParser { return false; } - public static ApplicationInfo generateApplicationInfo(Package p, int flags, boolean stopped, - int enabledState) { - return generateApplicationInfo(p, flags, stopped, enabledState, UserHandle.getCallingUserId()); + public static ApplicationInfo generateApplicationInfo(Package p, int flags, + PackageUserState state) { + return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId()); } public static ApplicationInfo generateApplicationInfo(Package p, int flags, - boolean stopped, int enabledState, int userId) { + PackageUserState state, int userId) { if (p == null) return null; - if (!copyNeeded(flags, p, enabledState, null) && userId == 0) { + if (!checkUseInstalled(flags, state)) { + return null; + } + if (!copyNeeded(flags, p, state, null, userId)) { // CompatibilityMode is global state. It's safe to modify the instance // of the package. if (!sCompatibilityModeEnabled) { p.applicationInfo.disableCompatibilityMode(); } - if (stopped) { - p.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED; - } else { - p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED; - } - if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { + // Make sure we report as installed. Also safe to do, since the + // default state should be installed (we will always copy if we + // need to report it is not installed). + p.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED; + if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { p.applicationInfo.enabled = true; - } else if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED - || enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { + } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED + || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { p.applicationInfo.enabled = false; } - p.applicationInfo.enabledSetting = enabledState; + p.applicationInfo.enabledSetting = state.enabled; return p.applicationInfo; } @@ -3520,18 +3553,23 @@ public class PackageParser { if (!sCompatibilityModeEnabled) { ai.disableCompatibilityMode(); } - if (stopped) { + if (state.stopped) { ai.flags |= ApplicationInfo.FLAG_STOPPED; } else { ai.flags &= ~ApplicationInfo.FLAG_STOPPED; } - if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { + if (state.installed) { + ai.flags |= ApplicationInfo.FLAG_INSTALLED; + } else { + ai.flags &= ~ApplicationInfo.FLAG_INSTALLED; + } + if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { ai.enabled = true; - } else if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED - || enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { + } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED + || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { ai.enabled = false; } - ai.enabledSetting = enabledState; + ai.enabledSetting = state.enabled; return ai; } @@ -3578,16 +3616,19 @@ public class PackageParser { } } - public static final ActivityInfo generateActivityInfo(Activity a, int flags, boolean stopped, - int enabledState, int userId) { + public static final ActivityInfo generateActivityInfo(Activity a, int flags, + PackageUserState state, int userId) { if (a == null) return null; - if (!copyNeeded(flags, a.owner, enabledState, a.metaData) && userId == 0) { + if (!checkUseInstalled(flags, state)) { + return null; + } + if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) { return a.info; } // Make shallow copies so we can store the metadata safely ActivityInfo ai = new ActivityInfo(a.info); ai.metaData = a.metaData; - ai.applicationInfo = generateApplicationInfo(a.owner, flags, stopped, enabledState, userId); + ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId); return ai; } @@ -3612,17 +3653,19 @@ public class PackageParser { } } - public static final ServiceInfo generateServiceInfo(Service s, int flags, boolean stopped, - int enabledState, int userId) { + public static final ServiceInfo generateServiceInfo(Service s, int flags, + PackageUserState state, int userId) { if (s == null) return null; - if (!copyNeeded(flags, s.owner, enabledState, s.metaData) - && userId == UserHandle.getUserId(s.info.applicationInfo.uid)) { + if (!checkUseInstalled(flags, state)) { + return null; + } + if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) { return s.info; } // Make shallow copies so we can store the metadata safely ServiceInfo si = new ServiceInfo(s.info); si.metaData = s.metaData; - si.applicationInfo = generateApplicationInfo(s.owner, flags, stopped, enabledState, userId); + si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId); return si; } @@ -3655,13 +3698,15 @@ public class PackageParser { } } - public static final ProviderInfo generateProviderInfo(Provider p, int flags, boolean stopped, - int enabledState, int userId) { + public static final ProviderInfo generateProviderInfo(Provider p, int flags, + PackageUserState state, int userId) { if (p == null) return null; - if (!copyNeeded(flags, p.owner, enabledState, p.metaData) + if (!checkUseInstalled(flags, state)) { + return null; + } + if (!copyNeeded(flags, p.owner, state, p.metaData, userId) && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0 - || p.info.uriPermissionPatterns == null) - && userId == 0) { + || p.info.uriPermissionPatterns == null)) { return p.info; } // Make shallow copies so we can store the metadata safely @@ -3670,7 +3715,7 @@ public class PackageParser { if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { pi.uriPermissionPatterns = null; } - pi.applicationInfo = generateApplicationInfo(p.owner, flags, stopped, enabledState, userId); + pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId); return pi; } diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java new file mode 100644 index 0000000..1a71bfb --- /dev/null +++ b/core/java/android/content/pm/PackageUserState.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm; + +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; + +import java.util.HashSet; + +/** + * Per-user state information about a package. + */ +public class PackageUserState { + public boolean stopped; + public boolean notLaunched; + public boolean installed; + public int enabled; + + public HashSet<String> disabledComponents; + public HashSet<String> enabledComponents; + + public PackageUserState() { + installed = true; + enabled = COMPONENT_ENABLED_STATE_DEFAULT; + } + + public PackageUserState(PackageUserState o) { + installed = o.installed; + stopped = o.stopped; + notLaunched = o.notLaunched; + enabled = o.enabled; + disabledComponents = o.disabledComponents != null + ? new HashSet<String>(o.disabledComponents) : null; + enabledComponents = o.enabledComponents != null + ? new HashSet<String>(o.enabledComponents) : null; + } +}
\ No newline at end of file diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index 0843d85..d33bd80 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -28,6 +28,9 @@ public final class UserHandle implements Parcelable { /** @hide A user id to indicate all users on the device */ public static final int USER_ALL = -1; + /** @hide A user handle to indicate all users on the device */ + public static final UserHandle ALL = new UserHandle(USER_ALL); + /** @hide A user id to indicate the currently active user */ public static final int USER_CURRENT = -2; diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java index 246b0c9..c5e7d9d 100644 --- a/core/java/com/android/internal/content/PackageHelper.java +++ b/core/java/com/android/internal/content/PackageHelper.java @@ -49,6 +49,7 @@ public class PackageHelper { public static final int RECOMMEND_FAILED_ALREADY_EXISTS = -4; public static final int RECOMMEND_MEDIA_UNAVAILABLE = -5; public static final int RECOMMEND_FAILED_INVALID_URI = -6; + public static final int RECOMMEND_FAILED_VERSION_DOWNGRADE = -7; private static final boolean localLOGV = true; private static final String TAG = "PackageHelper"; diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java index 6e1b9d6..a1fd14e 100755 --- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java +++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java @@ -864,7 +864,7 @@ public class PackageManagerTests extends AndroidTestCase { public void deleteFromRawResource(int iFlags, int dFlags) { InstallParams ip = sampleInstallFromRawResource(iFlags, false); - boolean retainData = ((dFlags & PackageManager.DONT_DELETE_DATA) != 0); + boolean retainData = ((dFlags & PackageManager.DELETE_KEEP_DATA) != 0); GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName); DeleteObserver observer = new DeleteObserver(); try { @@ -914,12 +914,12 @@ public class PackageManagerTests extends AndroidTestCase { @LargeTest public void testDeleteNormalInternalRetainData() { - deleteFromRawResource(0, PackageManager.DONT_DELETE_DATA); + deleteFromRawResource(0, PackageManager.DELETE_KEEP_DATA); } @LargeTest public void testDeleteFwdLockedInternalRetainData() { - deleteFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, PackageManager.DONT_DELETE_DATA); + deleteFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, PackageManager.DELETE_KEEP_DATA); } @LargeTest @@ -929,7 +929,7 @@ public class PackageManagerTests extends AndroidTestCase { return; } - deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.DONT_DELETE_DATA); + deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.DELETE_KEEP_DATA); } /* sdcard mount/unmount tests ******/ @@ -1656,7 +1656,7 @@ public class PackageManagerTests extends AndroidTestCase { false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED); // Delete the package now retaining data. GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName); - invokeDeletePackage(ip.pkg.packageName, PackageManager.DONT_DELETE_DATA, receiver); + invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver); assertTrue(invokeMovePackageFail(ip.pkg.packageName, moveFlags, result)); } catch (Exception e) { failStr(e); @@ -2532,7 +2532,7 @@ public class PackageManagerTests extends AndroidTestCase { GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName); try { - invokeDeletePackage(ip.pkg.packageName, PackageManager.DONT_DELETE_DATA, receiver); + invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver); } catch (Exception e) { failStr(e); } diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index a28b8a4..b36bd55 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -26,6 +26,7 @@ import android.content.pm.MacAuthenticatedInputStream; import android.content.pm.ContainerEncryptionParams; import android.content.pm.IPackageManager; import android.content.pm.LimitedLengthInputStream; +import android.content.pm.PackageCleanItem; import android.content.pm.PackageInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; @@ -181,6 +182,7 @@ public class DefaultContainerService extends IntentService { } ret.packageName = pkg.packageName; + ret.versionCode = pkg.versionCode; ret.installLocation = pkg.installLocation; ret.verifiers = pkg.verifiers; @@ -268,12 +270,14 @@ public class DefaultContainerService extends IntentService { if (PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE.equals(intent.getAction())) { IPackageManager pm = IPackageManager.Stub.asInterface( ServiceManager.getService("package")); - String pkg = null; + PackageCleanItem pkg = null; try { while ((pkg=pm.nextPackageToClean(pkg)) != null) { - eraseFiles(Environment.getExternalStorageAppDataDirectory(pkg)); - eraseFiles(Environment.getExternalStorageAppMediaDirectory(pkg)); - eraseFiles(Environment.getExternalStorageAppObbDirectory(pkg)); + eraseFiles(Environment.getExternalStorageAppDataDirectory(pkg.packageName)); + eraseFiles(Environment.getExternalStorageAppMediaDirectory(pkg.packageName)); + if (pkg.andCode) { + eraseFiles(Environment.getExternalStorageAppObbDirectory(pkg.packageName)); + } } } catch (RemoteException e) { } diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java index e222936..e6bcaa1 100644 --- a/services/java/com/android/server/am/ActiveServices.java +++ b/services/java/com/android/server/am/ActiveServices.java @@ -210,7 +210,7 @@ public class ActiveServices { ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, - int callingPid, int callingUid) { + int callingPid, int callingUid, int userId) { if (DEBUG_SERVICE) Slog.v(TAG, "startService: " + service + " type=" + resolvedType + " args=" + service.getExtras()); @@ -226,7 +226,7 @@ public class ActiveServices { ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, - callingPid, callingUid, UserHandle.getUserId(callingUid), true); + callingPid, callingUid, userId, true); if (res == null) { return null; } @@ -264,7 +264,7 @@ public class ActiveServices { } int stopServiceLocked(IApplicationThread caller, Intent service, - String resolvedType) { + String resolvedType, int userId) { if (DEBUG_SERVICE) Slog.v(TAG, "stopService: " + service + " type=" + resolvedType); @@ -278,9 +278,7 @@ public class ActiveServices { // If this service is active, make sure it is stopped. ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, - Binder.getCallingPid(), Binder.getCallingUid(), - callerApp == null ? UserHandle.getCallingUserId() : callerApp.userId, - false); + Binder.getCallingPid(), Binder.getCallingUid(), userId, false); if (r != null) { if (r.record != null) { final long origId = Binder.clearCallingIdentity(); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 8fc12d3..2b4f8b1 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -10554,7 +10554,7 @@ public final class ActivityManagerService extends ActivityManagerNative } public ComponentName startService(IApplicationThread caller, Intent service, - String resolvedType) { + String resolvedType, int userId) { enforceNotIsolatedCaller("startService"); // Refuse possible leaked file descriptors if (service != null && service.hasFileDescriptors() == true) { @@ -10566,9 +10566,10 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized(this) { final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); + checkValidCaller(callingUid, userId); final long origId = Binder.clearCallingIdentity(); ComponentName res = mServices.startServiceLocked(caller, service, - resolvedType, callingPid, callingUid); + resolvedType, callingPid, callingUid, userId); Binder.restoreCallingIdentity(origId); return res; } @@ -10581,22 +10582,24 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.v(TAG, "startServiceInPackage: " + service + " type=" + resolvedType); final long origId = Binder.clearCallingIdentity(); ComponentName res = mServices.startServiceLocked(null, service, - resolvedType, -1, uid); + resolvedType, -1, uid, UserHandle.getUserId(uid)); Binder.restoreCallingIdentity(origId); return res; } } public int stopService(IApplicationThread caller, Intent service, - String resolvedType) { + String resolvedType, int userId) { enforceNotIsolatedCaller("stopService"); // Refuse possible leaked file descriptors if (service != null && service.hasFileDescriptors() == true) { throw new IllegalArgumentException("File descriptors passed in Intent"); } + checkValidCaller(Binder.getCallingUid(), userId); + synchronized(this) { - return mServices.stopServiceLocked(caller, service, resolvedType); + return mServices.stopServiceLocked(caller, service, resolvedType, userId); } } diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 4252b90..b0aca21 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -64,11 +64,12 @@ import android.content.pm.IPackageManager; import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; import android.content.pm.InstrumentationInfo; +import android.content.pm.PackageCleanItem; import android.content.pm.PackageInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; import android.content.pm.PackageParser; -import android.content.pm.UserInfo; +import android.content.pm.PackageUserState; import android.content.pm.PackageParser.ActivityIntentInfo; import android.content.pm.PackageStats; import android.content.pm.ParceledListSlice; @@ -103,7 +104,6 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; -import android.os.UserManager; import android.provider.Settings.Secure; import android.security.SystemKeyStore; import android.util.DisplayMetrics; @@ -168,6 +168,7 @@ public class PackageManagerService extends IPackageManager.Stub { static final boolean DEBUG_UPGRADE = false; private static final boolean DEBUG_INSTALL = false; private static final boolean DEBUG_REMOVE = false; + private static final boolean DEBUG_BROADCASTS = false; private static final boolean DEBUG_SHOW_INFO = false; private static final boolean DEBUG_PACKAGE_INFO = false; private static final boolean DEBUG_INTENT_MATCHING = false; @@ -662,15 +663,21 @@ public class PackageManagerService extends IPackageManager.Stub { break; } case START_CLEANING_PACKAGE: { - String packageName = (String)msg.obj; Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); + PackageCleanItem item = new PackageCleanItem((String)msg.obj, + msg.arg2 != 0); synchronized (mPackages) { - if (!mSettings.mPackagesToBeCleaned.contains(packageName)) { - mSettings.mPackagesToBeCleaned.add(packageName); + if (msg.arg1 == UserHandle.USER_ALL) { + int[] users = sUserManager.getUserIds(); + for (int user : users) { + mSettings.addPackageToCleanLPw(user, item); + } + } else { + mSettings.addPackageToCleanLPw(msg.arg1, item); } } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - startCleaningPackages(); + startCleaningPackages(-1); } break; case POST_INSTALL: { if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1); @@ -692,15 +699,14 @@ public class PackageManagerService extends IPackageManager.Stub { } sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, res.pkg.applicationInfo.packageName, - extras, null, null, UserHandle.USER_ALL); + extras, null, null, res.users); if (update) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, res.pkg.applicationInfo.packageName, - extras, null, null, UserHandle.USER_ALL); + extras, null, null, res.users); sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, - res.pkg.applicationInfo.packageName, null, - UserHandle.USER_ALL); + res.pkg.applicationInfo.packageName, null, res.users); } if (res.removedInfo.args != null) { // Remove the replaced package's older resources safely now @@ -1562,19 +1568,17 @@ public class PackageManagerService extends IPackageManager.Stub { PackageInfo generatePackageInfo(PackageParser.Package p, int flags, int userId) { if (!sUserManager.exists(userId)) return null; PackageInfo pi; - if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { - // The package has been uninstalled but has retained data and resources. - pi = PackageParser.generatePackageInfo(p, null, flags, 0, 0, null, false, 0, userId); - } else { - final PackageSetting ps = (PackageSetting) p.mExtras; - if (ps == null) { - return null; - } - final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; - pi = PackageParser.generatePackageInfo(p, gp.gids, flags, - ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions, - ps.getStopped(userId), ps.getEnabled(userId), userId); - pi.applicationInfo.enabledSetting = ps.getEnabled(userId); + final PackageSetting ps = (PackageSetting) p.mExtras; + if (ps == null) { + return null; + } + final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; + final PackageUserState state = ps.readUserState(userId); + pi = PackageParser.generatePackageInfo(p, gp.gids, flags, + ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions, + state, userId); + if (pi != null) { + pi.applicationInfo.enabledSetting = state.enabled; pi.applicationInfo.enabled = pi.applicationInfo.enabledSetting == COMPONENT_ENABLED_STATE_DEFAULT || pi.applicationInfo.enabledSetting == COMPONENT_ENABLED_STATE_ENABLED; @@ -1741,14 +1745,15 @@ public class PackageManagerService extends IPackageManager.Stub { PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { if (ps.pkg == null) { - PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName, flags, userId); + PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName, + flags, userId); if (pInfo != null) { return pInfo.applicationInfo; } return null; } - return PackageParser.generateApplicationInfo(ps.pkg, flags, ps.getStopped(userId), - ps.getEnabled(userId), userId); + return PackageParser.generateApplicationInfo(ps.pkg, flags, + ps.readUserState(userId), userId); } return null; } @@ -1758,20 +1763,23 @@ public class PackageManagerService extends IPackageManager.Stub { if (!sUserManager.exists(userId)) return null; PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { - PackageParser.Package pkg = new PackageParser.Package(packageName); - if (ps.pkg == null) { - ps.pkg = new PackageParser.Package(packageName); - ps.pkg.applicationInfo.packageName = packageName; - ps.pkg.applicationInfo.flags = ps.pkgFlags; - ps.pkg.applicationInfo.publicSourceDir = ps.resourcePathString; - ps.pkg.applicationInfo.sourceDir = ps.codePathString; - ps.pkg.applicationInfo.dataDir = + PackageParser.Package pkg = ps.pkg; + if (pkg == null) { + if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) { + return null; + } + pkg = new PackageParser.Package(packageName); + pkg.applicationInfo.packageName = packageName; + pkg.applicationInfo.flags = ps.pkgFlags; + pkg.applicationInfo.publicSourceDir = ps.resourcePathString; + pkg.applicationInfo.sourceDir = ps.codePathString; + pkg.applicationInfo.dataDir = getDataPathForPackage(ps.pkg.packageName, 0).getPath(); - ps.pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString; + pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString; } - // ps.pkg.mSetEnabled = ps.getEnabled(userId); - // ps.pkg.mSetStopped = ps.getStopped(userId); - return generatePackageInfo(ps.pkg, flags, userId); + // pkg.mSetEnabled = ps.getEnabled(userId); + // pkg.mSetStopped = ps.getStopped(userId); + return generatePackageInfo(pkg, flags, userId); } return null; } @@ -1789,13 +1797,12 @@ public class PackageManagerService extends IPackageManager.Stub { PackageSetting ps = mSettings.mPackages.get(packageName); if (ps == null) return null; // Note: isEnabledLP() does not apply here - always return info - return PackageParser.generateApplicationInfo(p, flags, ps.getStopped(userId), - ps.getEnabled(userId)); + return PackageParser.generateApplicationInfo(p, flags, ps.readUserState(userId)); } if ("android".equals(packageName)||"system".equals(packageName)) { return mAndroidApplication; } - if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { + if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { return generateApplicationInfoFromSettingsLPw(packageName, flags, userId); } } @@ -1862,8 +1869,8 @@ public class PackageManagerService extends IPackageManager.Stub { if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; - return PackageParser.generateActivityInfo(a, flags, ps.getStopped(userId), - ps.getEnabled(userId), userId); + return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId), + userId); } if (mResolveComponentName.equals(component)) { return mResolveActivity; @@ -1882,8 +1889,8 @@ public class PackageManagerService extends IPackageManager.Stub { if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; - return PackageParser.generateActivityInfo(a, flags, ps.getStopped(userId), - ps.getEnabled(userId), userId); + return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId), + userId); } } return null; @@ -1899,8 +1906,8 @@ public class PackageManagerService extends IPackageManager.Stub { if (s != null && mSettings.isEnabledLPr(s.info, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; - return PackageParser.generateServiceInfo(s, flags, ps.getStopped(userId), - ps.getEnabled(userId), userId); + return PackageParser.generateServiceInfo(s, flags, ps.readUserState(userId), + userId); } } return null; @@ -1916,8 +1923,8 @@ public class PackageManagerService extends IPackageManager.Stub { if (p != null && mSettings.isEnabledLPr(p.info, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; - return PackageParser.generateProviderInfo(p, flags, ps.getStopped(userId), - ps.getEnabled(userId), userId); + return PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId), + userId); } } return null; @@ -2870,8 +2877,8 @@ public class PackageManagerService extends IPackageManager.Stub { } else { final PackageParser.Package p = mPackages.get(packageName); if (p != null && ps != null) { - ai = PackageParser.generateApplicationInfo(p, flags, ps.getStopped(userId), - ps.getEnabled(userId), userId); + ai = PackageParser.generateApplicationInfo(p, flags, + ps.readUserState(userId), userId); } } @@ -2901,10 +2908,13 @@ public class PackageManagerService extends IPackageManager.Stub { && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0 && (!mSafeMode || isSystemApp(p))) { PackageSetting ps = mSettings.mPackages.get(p.packageName); - finalList.add(PackageParser.generateApplicationInfo(p, flags, - ps != null ? ps.getStopped(userId) : false, - ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, - userId)); + if (ps != null) { + ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags, + ps.readUserState(userId), userId); + if (ai != null) { + finalList.add(ai); + } + } } } } @@ -2921,14 +2931,12 @@ public class PackageManagerService extends IPackageManager.Stub { PackageSetting ps = provider != null ? mSettings.mPackages.get(provider.owner.packageName) : null; - return provider != null + return ps != null && mSettings.isEnabledLPr(provider.info, flags, userId) && (!mSafeMode || (provider.info.applicationInfo.flags &ApplicationInfo.FLAG_SYSTEM) != 0) ? PackageParser.generateProviderInfo(provider, flags, - ps != null ? ps.getStopped(userId) : false, - ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, - userId) + ps.readUserState(userId), userId) : null; } } @@ -2948,14 +2956,15 @@ public class PackageManagerService extends IPackageManager.Stub { PackageParser.Provider p = entry.getValue(); PackageSetting ps = mSettings.mPackages.get(p.owner.packageName); - if (p.syncable + if (ps != null && p.syncable && (!mSafeMode || (p.info.applicationInfo.flags &ApplicationInfo.FLAG_SYSTEM) != 0)) { - outNames.add(entry.getKey()); - outInfo.add(PackageParser.generateProviderInfo(p, 0, - ps != null ? ps.getStopped(userId) : false, - ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, - userId)); + ProviderInfo info = PackageParser.generateProviderInfo(p, 0, + ps.readUserState(userId), userId); + if (info != null) { + outNames.add(entry.getKey()); + outInfo.add(info); + } } } } @@ -2973,7 +2982,7 @@ public class PackageManagerService extends IPackageManager.Stub { while (i.hasNext()) { final PackageParser.Provider p = i.next(); PackageSetting ps = mSettings.mPackages.get(p.owner.packageName); - if (p.info.authority != null + if (ps != null && p.info.authority != null && (processName == null || (p.info.processName.equals(processName) && UserHandle.isSameApp(p.info.applicationInfo.uid, uid))) @@ -2983,10 +2992,9 @@ public class PackageManagerService extends IPackageManager.Stub { if (finalList == null) { finalList = new ArrayList<ProviderInfo>(3); } - finalList.add(PackageParser.generateProviderInfo(p, flags, - ps != null ? ps.getStopped(userId) : false, - ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, - userId)); + ProviderInfo info = PackageParser.generateProviderInfo(p, flags, + ps.readUserState(userId), userId); + finalList.add(info); } } } @@ -3047,7 +3055,7 @@ public class PackageManagerService extends IPackageManager.Stub { continue; } PackageParser.Package pkg = scanPackageLI(file, - flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime); + flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null); // Don't mess around with apps in system partition. if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 && mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) { @@ -3115,7 +3123,7 @@ public class PackageManagerService extends IPackageManager.Stub { * Returns null in case of errors and the error code is stored in mLastScanError */ private PackageParser.Package scanPackageLI(File scanFile, - int parseFlags, int scanMode, long currentTime) { + int parseFlags, int scanMode, long currentTime, UserHandle user) { mLastScanError = PackageManager.INSTALL_SUCCEEDED; String scanPath = scanFile.getPath(); parseFlags |= mDefParseFlags; @@ -3215,7 +3223,7 @@ public class PackageManagerService extends IPackageManager.Stub { */ if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) { - deletePackageLI(pkg.packageName, true, 0, null, false); + deletePackageLI(pkg.packageName, null, true, 0, null, false); ps = null; } else { /* @@ -3268,7 +3276,7 @@ public class PackageManagerService extends IPackageManager.Stub { setApplicationInfoPaths(pkg, codePath, resPath); // Note that we invoke the following method only if we are about to unpack an application PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode - | SCAN_UPDATE_SIGNATURE, currentTime); + | SCAN_UPDATE_SIGNATURE, currentTime, user); /* * If the system app should be overridden by a previously installed @@ -3472,7 +3480,7 @@ public class PackageManagerService extends IPackageManager.Stub { } private PackageParser.Package scanPackageLI(PackageParser.Package pkg, - int parseFlags, int scanMode, long currentTime) { + int parseFlags, int scanMode, long currentTime, UserHandle user) { File scanFile = new File(pkg.mScanPath); if (scanFile == null || pkg.applicationInfo.sourceDir == null || pkg.applicationInfo.publicSourceDir == null) { @@ -3664,7 +3672,7 @@ public class PackageManagerService extends IPackageManager.Stub { // the PkgSetting exists already and doesn't have to be created. pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile, destResourceFile, pkg.applicationInfo.nativeLibraryDir, - pkg.applicationInfo.flags, true, false); + pkg.applicationInfo.flags, user, false); if (pkgSetting == null) { Slog.w(TAG, "Creating application package " + pkg.packageName + " failed"); mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; @@ -4024,7 +4032,9 @@ public class PackageManagerService extends IPackageManager.Stub { // Add the new setting to mPackages mPackages.put(pkg.applicationInfo.packageName, pkg); // Make sure we don't accidentally delete its data. - mSettings.mPackagesToBeCleaned.remove(pkgName); + for (int i=0; i<mSettings.mPackagesToBeCleaned.size(); i++) { + mSettings.mPackagesToBeCleaned.valueAt(i).remove(pkgName); + } // Take care of first install / last update times. if (currentTime != 0) { @@ -4840,7 +4850,8 @@ public class PackageManagerService extends IPackageManager.Stub { // System apps are never considered stopped for purposes of // filtering, because there may be no way for the user to // actually re-launch them. - return ps.getStopped(userId) && (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0; + return (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0 + && ps.getStopped(userId); } } return false; @@ -4863,12 +4874,17 @@ public class PackageManagerService extends IPackageManager.Stub { &ApplicationInfo.FLAG_SYSTEM) == 0) { return null; } - final ResolveInfo res = new ResolveInfo(); PackageSetting ps = (PackageSetting) activity.owner.mExtras; - res.activityInfo = PackageParser.generateActivityInfo(activity, mFlags, - ps != null ? ps.getStopped(userId) : false, - ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, - userId); + if (ps == null) { + return null; + } + ActivityInfo ai = PackageParser.generateActivityInfo(activity, mFlags, + ps.readUserState(userId), userId); + if (ai == null) { + return null; + } + final ResolveInfo res = new ResolveInfo(); + res.activityInfo = ai; if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) { res.filter = info; } @@ -5031,8 +5047,8 @@ public class PackageManagerService extends IPackageManager.Stub { // System apps are never considered stopped for purposes of // filtering, because there may be no way for the user to // actually re-launch them. - return ps.getStopped(userId) - && (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0; + return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 + && ps.getStopped(userId); } } return false; @@ -5056,12 +5072,14 @@ public class PackageManagerService extends IPackageManager.Stub { &ApplicationInfo.FLAG_SYSTEM) == 0) { return null; } - final ResolveInfo res = new ResolveInfo(); PackageSetting ps = (PackageSetting) service.owner.mExtras; - res.serviceInfo = PackageParser.generateServiceInfo(service, mFlags, - ps != null ? ps.getStopped(userId) : false, - ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, - userId); + if (ps == null) { + return null; + } + ServiceInfo si = PackageParser.generateServiceInfo(service, mFlags, + ps.readUserState(userId), userId); + final ResolveInfo res = new ResolveInfo(); + res.serviceInfo = si; if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) { res.filter = filter; } @@ -5152,13 +5170,14 @@ public class PackageManagerService extends IPackageManager.Stub { }; static final void sendPackageBroadcast(String action, String pkg, - Bundle extras, String targetPkg, IIntentReceiver finishedReceiver, int userId) { + Bundle extras, String targetPkg, IIntentReceiver finishedReceiver, + int[] userIds) { IActivityManager am = ActivityManagerNative.getDefault(); if (am != null) { try { - int[] userIds = userId == UserHandle.USER_ALL - ? sUserManager.getUserIds() - : new int[] {userId}; + if (userIds == null) { + userIds = sUserManager.getUserIds(); + } for (int id : userIds) { final Intent intent = new Intent(action, pkg != null ? Uri.fromParts("package", pkg, null) : null); @@ -5170,11 +5189,18 @@ public class PackageManagerService extends IPackageManager.Stub { } // Modify the UID when posting to other users int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); - if (uid > 0 && id > 0) { + if (uid > 0 && UserHandle.getUserId(uid) != id) { uid = UserHandle.getUid(id, UserHandle.getAppId(uid)); intent.putExtra(Intent.EXTRA_UID, uid); } intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + if (DEBUG_BROADCASTS) { + RuntimeException here = new RuntimeException("here"); + here.fillInStackTrace(); + Slog.d(TAG, "Sending to user " + id + ": " + + intent.toShortString(false, true, false, false) + + " " + intent.getExtras(), here); + } am.broadcastIntent(null, intent, null, finishedReceiver, 0, null, null, null, finishedReceiver != null, false, id); } @@ -5192,8 +5218,9 @@ public class PackageManagerService extends IPackageManager.Stub { return mMediaMounted || Environment.isExternalStorageEmulated(); } - public String nextPackageToClean(String lastPackage) { + public PackageCleanItem nextPackageToClean(PackageCleanItem lastPackage) { // writer + final int userId = UserHandle.getCallingUserId(); synchronized (mPackages) { if (!isExternalMediaAvailable()) { // If the external storage is no longer mounted at this point, @@ -5201,34 +5228,65 @@ public class PackageManagerService extends IPackageManager.Stub { // packages files and can not delete any more. Bail. return null; } - if (lastPackage != null) { - mSettings.mPackagesToBeCleaned.remove(lastPackage); + ArrayList<PackageCleanItem> pkgs = mSettings.mPackagesToBeCleaned.get(userId); + if (pkgs != null) { + if (lastPackage != null) { + pkgs.remove(lastPackage); + } + if (pkgs.size() > 0) { + return pkgs.get(0); + } } - return mSettings.mPackagesToBeCleaned.size() > 0 - ? mSettings.mPackagesToBeCleaned.get(0) : null; } + // Move on to the next user to clean. + long ident = Binder.clearCallingIdentity(); + try { + startCleaningPackages(userId); + } finally { + Binder.restoreCallingIdentity(ident); + } + return null; } - void schedulePackageCleaning(String packageName) { - mHandler.sendMessage(mHandler.obtainMessage(START_CLEANING_PACKAGE, packageName)); + void schedulePackageCleaning(String packageName, int userId, boolean andCode) { + if (false) { + RuntimeException here = new RuntimeException("here"); + here.fillInStackTrace(); + Slog.d(TAG, "Schedule cleaning " + packageName + " user=" + userId + + " andCode=" + andCode, here); + } + mHandler.sendMessage(mHandler.obtainMessage(START_CLEANING_PACKAGE, + userId, andCode ? 1 : 0, packageName)); } - void startCleaningPackages() { + void startCleaningPackages(int lastUser) { // reader + int nextUser = -1; synchronized (mPackages) { if (!isExternalMediaAvailable()) { return; } - if (mSettings.mPackagesToBeCleaned.size() <= 0) { + final int N = mSettings.mPackagesToBeCleaned.size(); + if (N <= 0) { return; } + for (int i=0; i<N; i++) { + int user = mSettings.mPackagesToBeCleaned.keyAt(i); + if (user > lastUser) { + nextUser = user; + break; + } + } + if (nextUser < 0) { + nextUser = mSettings.mPackagesToBeCleaned.keyAt(0); + } } Intent intent = new Intent(PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE); intent.setComponent(DEFAULT_CONTAINER_COMPONENT); IActivityManager am = ActivityManagerNative.getDefault(); if (am != null) { try { - am.startService(null, intent, null); + am.startService(null, intent, null, nextUser); } catch (RemoteException e) { } } @@ -5291,7 +5349,7 @@ public class PackageManagerService extends IPackageManager.Stub { PackageParser.PARSE_CHATTY | PackageParser.PARSE_MUST_BE_APK, SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME, - System.currentTimeMillis()); + System.currentTimeMillis(), null); if (p != null) { /* * TODO this seems dangerous as the package may have @@ -5320,13 +5378,13 @@ public 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, null, UserHandle.USER_ALL); + extras, null, null, null); } if (addedPackage != null) { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, addedUid); sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, - extras, null, null, UserHandle.USER_ALL); + extras, null, null, null); } } @@ -5365,6 +5423,12 @@ public class PackageManagerService extends IPackageManager.Stub { null); final int uid = Binder.getCallingUid(); + UserHandle user; + if ((flags&PackageManager.INSTALL_ALL_USERS) != 0) { + user = UserHandle.ALL; + } else { + user = Process.myUserHandle(); + } final int filteredFlags; @@ -5379,10 +5443,51 @@ public class PackageManagerService extends IPackageManager.Stub { final Message msg = mHandler.obtainMessage(INIT_COPY); msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName, - verificationParams, encryptionParams); + verificationParams, encryptionParams, user); mHandler.sendMessage(msg); } + /** + * @hide + */ + @Override + public int installExistingPackage(String packageName) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, + null); + PackageSetting pkgSetting; + final int uid = Binder.getCallingUid(); + final int userId = UserHandle.getUserId(uid); + + long callingId = Binder.clearCallingIdentity(); + try { + boolean sendAdded = false; + Bundle extras = new Bundle(1); + + // writer + synchronized (mPackages) { + pkgSetting = mSettings.mPackages.get(packageName); + if (pkgSetting == null) { + return PackageManager.INSTALL_FAILED_INVALID_URI; + } + if (!pkgSetting.getInstalled(userId)) { + pkgSetting.setInstalled(true, userId); + mSettings.writePackageRestrictionsLPr(userId); + extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userId, pkgSetting.appId)); + sendAdded = true; + } + } + + if (sendAdded) { + sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, + packageName, extras, null, null, new int[] {userId}); + } + } finally { + Binder.restoreCallingIdentity(callingId); + } + + return PackageManager.INSTALL_SUCCEEDED; + } + @Override public void verifyPendingInstall(int id, int verificationCode) throws RemoteException { final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED); @@ -5840,17 +5945,19 @@ public class PackageManagerService extends IPackageManager.Stub { private int mRet; private File mTempPackage; final ContainerEncryptionParams encryptionParams; + final UserHandle user; InstallParams(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName, VerificationParams verificationParams, - ContainerEncryptionParams encryptionParams) { + ContainerEncryptionParams encryptionParams, UserHandle user) { this.mPackageURI = packageURI; this.flags = flags; this.observer = observer; this.installerPackageName = installerPackageName; this.verificationParams = verificationParams; this.encryptionParams = encryptionParams; + this.user = user; } public ManifestDigest getManifestDigest() { @@ -5860,6 +5967,10 @@ public class PackageManagerService extends IPackageManager.Stub { return verificationParams.getManifestDigest(); } + public UserHandle getUser() { + return user; + } + private int installLocationPolicy(PackageInfoLite pkgLite, int flags) { String packageName = pkgLite.packageName; int installLocation = pkgLite.installLocation; @@ -5869,6 +5980,16 @@ public class PackageManagerService extends IPackageManager.Stub { PackageParser.Package pkg = mPackages.get(packageName); if (pkg != null) { if ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { + // Check for downgrading. + if ((flags & PackageManager.INSTALL_ALLOW_DOWNGRADE) == 0) { + if (pkgLite.versionCode < pkg.mVersionCode) { + Slog.w(TAG, "Can't install update of " + packageName + + " update version " + pkgLite.versionCode + + " is older than installed version " + + pkg.mVersionCode); + return PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE; + } + } // Check for updated system application. if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { if (onSd) { @@ -5995,6 +6116,8 @@ public class PackageManagerService extends IPackageManager.Stub { ret = PackageManager.INSTALL_FAILED_INVALID_URI; } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) { ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE; + } else if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) { + ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE; } else { // Override with defaults if needed. loc = installLocationPolicy(pkgLite, flags); @@ -6338,14 +6461,17 @@ public class PackageManagerService extends IPackageManager.Stub { final Uri packageURI; final String installerPackageName; final ManifestDigest manifestDigest; + final UserHandle user; InstallArgs(Uri packageURI, IPackageInstallObserver observer, int flags, - String installerPackageName, ManifestDigest manifestDigest) { + String installerPackageName, ManifestDigest manifestDigest, + UserHandle user) { this.packageURI = packageURI; this.flags = flags; this.observer = observer; this.installerPackageName = installerPackageName; this.manifestDigest = manifestDigest; + this.user = user; } abstract void createCopyFile(); @@ -6396,11 +6522,12 @@ public class PackageManagerService extends IPackageManager.Stub { FileInstallArgs(InstallParams params) { super(params.getPackageUri(), params.observer, params.flags, - params.installerPackageName, params.getManifestDigest()); + params.installerPackageName, params.getManifestDigest(), + params.getUser()); } FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) { - super(null, null, 0, null, null); + super(null, null, 0, null, null, null); File codeFile = new File(fullCodePath); installDir = codeFile.getParentFile(); codeFileName = fullCodePath; @@ -6409,7 +6536,7 @@ public class PackageManagerService extends IPackageManager.Stub { } FileInstallArgs(Uri packageURI, String pkgName, String dataDir) { - super(packageURI, null, 0, null, null); + super(packageURI, null, 0, null, null, null); installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir; String apkName = getNextCodePath(null, pkgName, ".apk"); codeFileName = new File(installDir, apkName + ".apk").getPath(); @@ -6683,13 +6810,15 @@ public class PackageManagerService extends IPackageManager.Stub { AsecInstallArgs(InstallParams params) { super(params.getPackageUri(), params.observer, params.flags, - params.installerPackageName, params.getManifestDigest()); + params.installerPackageName, params.getManifestDigest(), + params.getUser()); } AsecInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath, boolean isExternal, boolean isForwardLocked) { super(null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0) - | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), null, null); + | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), + null, null, null); // Extract cid from fullCodePath int eidx = fullCodePath.lastIndexOf("/"); String subStr1 = fullCodePath.substring(0, eidx); @@ -6700,14 +6829,16 @@ public class PackageManagerService extends IPackageManager.Stub { AsecInstallArgs(String cid, boolean isForwardLocked) { super(null, null, (isAsecExternal(cid) ? PackageManager.INSTALL_EXTERNAL : 0) - | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), null, null); + | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), + null, null, null); this.cid = cid; setCachePath(PackageHelper.getSdDir(cid)); } AsecInstallArgs(Uri packageURI, String cid, boolean isExternal, boolean isForwardLocked) { super(packageURI, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0) - | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), null, null); + | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), + null, null, null); this.cid = cid; } @@ -7031,6 +7162,7 @@ public class PackageManagerService extends IPackageManager.Stub { class PackageInstalledInfo { String name; int uid; + int[] users; PackageParser.Package pkg; int returnCode; PackageRemovedInfo removedInfo; @@ -7040,14 +7172,12 @@ public class PackageManagerService extends IPackageManager.Stub { * Install a non-existing package. */ private void installNewPackageLI(PackageParser.Package pkg, - int parseFlags, - int scanMode, + int parseFlags, int scanMode, UserHandle user, String installerPackageName, PackageInstalledInfo res) { // Remember this for later, in case we need to rollback this install String pkgName = pkg.packageName; boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists(); - res.name = pkgName; synchronized(mPackages) { if (mSettings.mRenamedPackages.containsKey(pkgName)) { // A package with the same name is already installed, though @@ -7070,7 +7200,7 @@ public class PackageManagerService extends IPackageManager.Stub { } mLastScanError = PackageManager.INSTALL_SUCCEEDED; PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode, - System.currentTimeMillis()); + System.currentTimeMillis(), user); if (newPackage == null) { Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath); if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { @@ -7087,17 +7217,15 @@ public class PackageManagerService extends IPackageManager.Stub { // delete the package data and cache directories that it created in // scanPackageLocked, unless those directories existed before we even tried to // install. - deletePackageLI( - pkgName, false, - dataDirExists ? PackageManager.DONT_DELETE_DATA : 0, + deletePackageLI(pkgName, UserHandle.ALL, false, + dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0, res.removedInfo, true); } } } private void replacePackageLI(PackageParser.Package pkg, - int parseFlags, - int scanMode, + int parseFlags, int scanMode, UserHandle user, String installerPackageName, PackageInstalledInfo res) { PackageParser.Package oldPackage; @@ -7114,15 +7242,16 @@ public class PackageManagerService extends IPackageManager.Stub { } boolean sysPkg = (isSystemApp(oldPackage)); if (sysPkg) { - replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, installerPackageName, res); + replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, + user, installerPackageName, res); } else { - replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, installerPackageName, res); + replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, + user, installerPackageName, res); } } private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage, - PackageParser.Package pkg, - int parseFlags, int scanMode, + PackageParser.Package pkg, int parseFlags, int scanMode, UserHandle user, String installerPackageName, PackageInstalledInfo res) { PackageParser.Package newPackage = null; String pkgName = deletedPackage.packageName; @@ -7137,7 +7266,7 @@ public class PackageManagerService extends IPackageManager.Stub { } // First delete the existing package while retaining the data directory - if (!deletePackageLI(pkgName, true, PackageManager.DONT_DELETE_DATA, + if (!deletePackageLI(pkgName, null, true, PackageManager.DELETE_KEEP_DATA, res.removedInfo, true)) { // If the existing package wasn't successfully deleted res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE; @@ -7146,7 +7275,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Successfully deleted the old package. Now proceed with re-installation mLastScanError = PackageManager.INSTALL_SUCCEEDED; newPackage = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_TIME, - System.currentTimeMillis()); + System.currentTimeMillis(), user); if (newPackage == null) { Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath); if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { @@ -7167,8 +7296,8 @@ public class PackageManagerService extends IPackageManager.Stub { // install. if(updatedSettings) { deletePackageLI( - pkgName, true, - PackageManager.DONT_DELETE_DATA, + pkgName, null, true, + PackageManager.DELETE_KEEP_DATA, res.removedInfo, true); } // Since we failed to install the new package we need to restore the old @@ -7183,7 +7312,7 @@ public class PackageManagerService extends IPackageManager.Stub { int oldScanMode = (oldOnSd ? 0 : SCAN_MONITOR) | SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME; if (scanPackageLI(restoreFile, oldParseFlags, oldScanMode, - origUpdateTime) == null) { + origUpdateTime, user) == null) { Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade"); return; } @@ -7201,8 +7330,7 @@ public class PackageManagerService extends IPackageManager.Stub { } private void replaceSystemPackageLI(PackageParser.Package deletedPackage, - PackageParser.Package pkg, - int parseFlags, int scanMode, + PackageParser.Package pkg, int parseFlags, int scanMode, UserHandle user, String installerPackageName, PackageInstalledInfo res) { PackageParser.Package newPackage = null; boolean updatedSettings = false; @@ -7251,7 +7379,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Successfully disabled the old package. Now proceed with re-installation mLastScanError = PackageManager.INSTALL_SUCCEEDED; pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; - newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0); + newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0, user); if (newPackage == null) { Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath); if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { @@ -7274,7 +7402,7 @@ public class PackageManagerService extends IPackageManager.Stub { removePackageLI(newPackage, true); } // Add back the old system package - scanPackageLI(oldPkg, parseFlags, SCAN_MONITOR | SCAN_UPDATE_SIGNATURE, 0); + scanPackageLI(oldPkg, parseFlags, SCAN_MONITOR | SCAN_UPDATE_SIGNATURE, 0, user); // Restore the old system information in Settings synchronized(mPackages) { if (updatedSettings) { @@ -7333,6 +7461,10 @@ public class PackageManagerService extends IPackageManager.Stub { UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0 ? UPDATE_PERMISSIONS_ALL : 0)); res.name = pkgName; + PackageSetting ps = mSettings.mPackages.get(pkgName); + if (ps != null) { + res.users = ps.getInstalledUsers(sUserManager.getUserIds()); + } res.uid = newPackage.applicationInfo.uid; res.pkg = newPackage; mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE); @@ -7448,12 +7580,18 @@ public class PackageManagerService extends IPackageManager.Stub { setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath()); pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath(); if (replace) { - replacePackageLI(pkg, parseFlags, scanMode, + replacePackageLI(pkg, parseFlags, scanMode, args.user, installerPackageName, res); } else { - installNewPackageLI(pkg, parseFlags, scanMode, + installNewPackageLI(pkg, parseFlags, scanMode, args.user, installerPackageName,res); } + synchronized (mPackages) { + PackageSetting ps = mSettings.mPackages.get(pkgName); + if (ps != null) { + res.users = ps.getInstalledUsers(sUserManager.getUserIds()); + } + } } private static boolean isForwardLocked(PackageParser.Package pkg) { @@ -7544,10 +7682,11 @@ public class PackageManagerService extends IPackageManager.Stub { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DELETE_PACKAGES, null); // Queue up an async operation since the package deletion may take a little while. + final int uid = Binder.getCallingUid(); mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); - final int returnCode = deletePackageX(packageName, true, true, flags); + final int returnCode = deletePackageX(packageName, uid, flags); if (observer != null) { try { observer.packageDeleted(packageName, returnCode); @@ -7573,8 +7712,7 @@ public class PackageManagerService extends IPackageManager.Stub { * persisting settings for later use * sending a broadcast if necessary */ - private int deletePackageX(String packageName, boolean sendBroadCast, - boolean deleteCodeAndResources, int flags) { + private int deletePackageX(String packageName, int uid, int flags) { final PackageRemovedInfo info = new PackageRemovedInfo(); final boolean res; @@ -7589,27 +7727,30 @@ public class PackageManagerService extends IPackageManager.Stub { } synchronized (mInstallLock) { - res = deletePackageLI(packageName, deleteCodeAndResources, - flags | REMOVE_CHATTY, info, true); + res = deletePackageLI(packageName, + (flags & PackageManager.DELETE_ALL_USERS) != 0 + ? UserHandle.ALL : new UserHandle(UserHandle.getUserId(uid)), + true, flags | REMOVE_CHATTY, info, true); } - if (res && sendBroadCast) { + if (res) { boolean systemUpdate = info.isRemovedPackageSystemUpdate; - info.sendBroadcast(deleteCodeAndResources, systemUpdate); + info.sendBroadcast(true, systemUpdate); // If the removed package was a system update, the old system packaged // was re-enabled; we need to broadcast this information if (systemUpdate) { Bundle extras = new Bundle(1); - extras.putInt(Intent.EXTRA_UID, info.removedUid >= 0 ? info.removedUid : info.uid); + extras.putInt(Intent.EXTRA_UID, info.removedAppId >= 0 + ? info.removedAppId : info.uid); extras.putBoolean(Intent.EXTRA_REPLACING, true); sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, - extras, null, null, UserHandle.USER_ALL); + extras, null, null, null); sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, - extras, null, null, UserHandle.USER_ALL); + extras, null, null, null); sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, - null, packageName, null, UserHandle.USER_ALL); + null, packageName, null, null); } } // Force a gc here. @@ -7618,7 +7759,7 @@ public class PackageManagerService extends IPackageManager.Stub { // other processes clean up before deleting resources. if (info.args != null) { synchronized (mInstallLock) { - info.args.doPostDeleteLI(deleteCodeAndResources); + info.args.doPostDeleteLI(true); } } @@ -7628,29 +7769,30 @@ public class PackageManagerService extends IPackageManager.Stub { static class PackageRemovedInfo { String removedPackage; int uid = -1; - int removedUid = -1; + int removedAppId = -1; + int[] removedUsers = null; boolean isRemovedPackageSystemUpdate = false; // Clean up resources deleted packages. InstallArgs args = null; void sendBroadcast(boolean fullRemove, boolean replacing) { Bundle extras = new Bundle(1); - extras.putInt(Intent.EXTRA_UID, removedUid >= 0 ? removedUid : uid); + extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid); extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove); if (replacing) { extras.putBoolean(Intent.EXTRA_REPLACING, true); } if (removedPackage != null) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, - extras, null, null, UserHandle.USER_ALL); + extras, null, null, removedUsers); if (fullRemove && !replacing) { sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage, - extras, null, null, UserHandle.USER_ALL); + extras, null, null, removedUsers); } } - if (removedUid >= 0) { + if (removedAppId >= 0) { sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null, - UserHandle.getUserId(removedUid)); + removedUsers); } } } @@ -7664,17 +7806,19 @@ public class PackageManagerService extends IPackageManager.Stub { private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo, int flags, boolean writeSettings) { String packageName = p.packageName; - if (outInfo != null) { - outInfo.removedPackage = packageName; - } removePackageLI(p, (flags&REMOVE_CHATTY) != 0); // Retrieve object to delete permissions for shared user later on final PackageSetting deletedPs; // reader synchronized (mPackages) { deletedPs = mSettings.mPackages.get(packageName); + if (outInfo != null) { + outInfo.removedPackage = packageName; + outInfo.removedUsers = deletedPs != null + ? deletedPs.getInstalledUsers(sUserManager.getUserIds()) : null; + } } - if ((flags&PackageManager.DONT_DELETE_DATA) == 0) { + if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) { int retCode = mInstaller.remove(packageName, 0); if (retCode < 0) { Slog.w(TAG, "Couldn't remove app data or cache directory for package: " @@ -7684,14 +7828,14 @@ public class PackageManagerService extends IPackageManager.Stub { // TODO: Kill the processes first sUserManager.removePackageForAllUsers(packageName); } - schedulePackageCleaning(packageName); + schedulePackageCleaning(packageName, UserHandle.USER_ALL, true); } // writer synchronized (mPackages) { if (deletedPs != null) { - if ((flags&PackageManager.DONT_DELETE_DATA) == 0) { + if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) { if (outInfo != null) { - outInfo.removedUid = mSettings.removePackageLPw(packageName); + outInfo.removedAppId = mSettings.removePackageLPw(packageName); } if (deletedPs != null) { updatePermissionsLPw(deletedPs.name, null, 0); @@ -7740,10 +7884,10 @@ public class PackageManagerService extends IPackageManager.Stub { outInfo.isRemovedPackageSystemUpdate = true; if (ps.versionCode < p.mVersionCode) { // Delete data for downgrades - flags &= ~PackageManager.DONT_DELETE_DATA; + flags &= ~PackageManager.DELETE_KEEP_DATA; } else { // Preserve data by setting flag - flags |= PackageManager.DONT_DELETE_DATA; + flags |= PackageManager.DELETE_KEEP_DATA; } boolean ret = deleteInstalledPackageLI(p, true, flags, outInfo, writeSettings); @@ -7760,7 +7904,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Install the system package PackageParser.Package newPkg = scanPackageLI(ps.codePath, PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM, - SCAN_MONITOR | SCAN_NO_PATHS, 0); + SCAN_MONITOR | SCAN_NO_PATHS, 0, null); if (newPkg == null) { Slog.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError); @@ -7807,7 +7951,7 @@ public class PackageManagerService extends IPackageManager.Stub { /* * This method handles package deletion in general */ - private boolean deletePackageLI(String packageName, + private boolean deletePackageLI(String packageName, UserHandle user, boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo, boolean writeSettings) { if (packageName == null) { @@ -7816,6 +7960,8 @@ public class PackageManagerService extends IPackageManager.Stub { } PackageParser.Package p; boolean dataOnly = false; + int removeUser = -1; + int appId = -1; synchronized (mPackages) { p = mPackages.get(packageName); if (p == null) { @@ -7823,15 +7969,53 @@ public class PackageManagerService extends IPackageManager.Stub { dataOnly = true; PackageSetting ps = mSettings.mPackages.get(packageName); if (ps == null) { - Slog.w(TAG, "Package named '" + packageName +"' doesn't exist."); + Slog.w(TAG, "Package named '" + packageName + "' doesn't exist."); return false; } p = ps.pkg; } + if (p == null) { + Slog.w(TAG, "Package named '" + packageName + "' doesn't exist."); + return false; + } + final PackageSetting ps = (PackageSetting)p.mExtras; + if (!isSystemApp(p) && ps != null && user != null + && user.getIdentifier() != UserHandle.USER_ALL) { + // The caller is asking that the package only be deleted for a single + // user. To do this, we just mark its uninstalled state and delete + // its data. + ps.setUserState(user.getIdentifier(), + COMPONENT_ENABLED_STATE_DEFAULT, + false, //installed + true, //stopped + true, //notLaunched + null, null); + if (ps.isAnyInstalled(sUserManager.getUserIds())) { + // Other user still have this package installed, so all + // we need to do is clear this user's data and save that + // it is uninstalled. + removeUser = user.getIdentifier(); + appId = ps.appId; + mSettings.writePackageRestrictionsLPr(removeUser); + } else { + // We need to set it back to 'installed' so the uninstall + // broadcasts will be sent correctly. + ps.setInstalled(true, user.getIdentifier()); + } + } } - if (p == null) { - Slog.w(TAG, "Package named '" + packageName +"' doesn't exist."); - return false; + + if (removeUser >= 0) { + // From above, we determined that we are deleting this only + // for a single user. Continue the work here. + if (outInfo != null) { + outInfo.removedPackage = packageName; + outInfo.removedAppId = appId; + outInfo.removedUsers = new int[] {removeUser}; + } + mInstaller.clearUserData(packageName, removeUser); + schedulePackageCleaning(packageName, removeUser, false); + return true; } if (dataOnly) { @@ -7876,7 +8060,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private void clearExternalStorageDataSync(String packageName, boolean allData) { + private void clearExternalStorageDataSync(String packageName, int userId, boolean allData) { final boolean mounted; if (Environment.isExternalStorageEmulated()) { mounted = true; @@ -7892,44 +8076,52 @@ public class PackageManagerService extends IPackageManager.Stub { } final Intent containerIntent = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); - ClearStorageConnection conn = new ClearStorageConnection(); - if (mContext.bindService(containerIntent, conn, Context.BIND_AUTO_CREATE)) { - try { - long timeout = SystemClock.uptimeMillis() + 5000; - synchronized (conn) { - long now = SystemClock.uptimeMillis(); - while (conn.mContainerService == null && now < timeout) { - try { - conn.wait(timeout - now); - } catch (InterruptedException e) { + int[] users; + if (userId == UserHandle.USER_ALL) { + users = sUserManager.getUserIds(); + } else { + users = new int[] { userId }; + } + for (int curUser : users) { + ClearStorageConnection conn = new ClearStorageConnection(); + if (mContext.bindService(containerIntent, conn, Context.BIND_AUTO_CREATE, curUser)) { + try { + long timeout = SystemClock.uptimeMillis() + 5000; + synchronized (conn) { + long now = SystemClock.uptimeMillis(); + while (conn.mContainerService == null && now < timeout) { + try { + conn.wait(timeout - now); + } catch (InterruptedException e) { + } } } - } - if (conn.mContainerService == null) { - return; - } - final File externalCacheDir = Environment - .getExternalStorageAppCacheDirectory(packageName); - try { - conn.mContainerService.clearDirectory(externalCacheDir.toString()); - } catch (RemoteException e) { - } - if (allData) { - final File externalDataDir = Environment - .getExternalStorageAppDataDirectory(packageName); - try { - conn.mContainerService.clearDirectory(externalDataDir.toString()); - } catch (RemoteException e) { + if (conn.mContainerService == null) { + return; } - final File externalMediaDir = Environment - .getExternalStorageAppMediaDirectory(packageName); + final File externalCacheDir = Environment + .getExternalStorageAppCacheDirectory(packageName); try { - conn.mContainerService.clearDirectory(externalMediaDir.toString()); + conn.mContainerService.clearDirectory(externalCacheDir.toString()); } catch (RemoteException e) { } + if (allData) { + final File externalDataDir = Environment + .getExternalStorageAppDataDirectory(packageName); + try { + conn.mContainerService.clearDirectory(externalDataDir.toString()); + } catch (RemoteException e) { + } + final File externalMediaDir = Environment + .getExternalStorageAppMediaDirectory(packageName); + try { + conn.mContainerService.clearDirectory(externalMediaDir.toString()); + } catch (RemoteException e) { + } + } + } finally { + mContext.unbindService(conn); } - } finally { - mContext.unbindService(conn); } } } @@ -7948,7 +8140,7 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mInstallLock) { succeeded = clearApplicationUserDataLI(packageName, userId); } - clearExternalStorageDataSync(packageName, true); + clearExternalStorageDataSync(packageName, userId, true); if (succeeded) { // invoke DeviceStorageMonitor's update method to clear any notifications DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) @@ -8022,7 +8214,7 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mInstallLock) { succeded = deleteApplicationCacheFilesLI(packageName, userId); } - clearExternalStorageDataSync(packageName, false); + clearExternalStorageDataSync(packageName, userId, false); if(observer != null) { try { observer.onRemoveCompleted(packageName, succeded); @@ -8480,7 +8672,7 @@ public class PackageManagerService extends IPackageManager.Stub { extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag); extras.putInt(Intent.EXTRA_UID, packageUid); sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, null, null, - UserHandle.getUserId(packageUid)); + new int[] {UserHandle.getUserId(packageUid)}); } public void setPackageStoppedState(String packageName, boolean stopped, int userId) { @@ -9085,7 +9277,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages"); loadMediaPackages(processCids, uidArr, removeCids); - startCleaningPackages(); + startCleaningPackages(-1); } else { if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages"); @@ -9106,7 +9298,7 @@ public class PackageManagerService extends IPackageManager.Stub { } String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE; - sendPackageBroadcast(action, null, extras, null, finishedReceiver, UserHandle.USER_ALL); + sendPackageBroadcast(action, null, extras, null, finishedReceiver, null); } } @@ -9151,7 +9343,7 @@ public class PackageManagerService extends IPackageManager.Stub { doGc = true; synchronized (mInstallLock) { final PackageParser.Package pkg = scanPackageLI(new File(codePath), parseFlags, - 0, 0); + 0, 0, null); // Scan the package if (pkg != null) { /* @@ -9260,8 +9452,8 @@ public class PackageManagerService extends IPackageManager.Stub { // Delete package internally PackageRemovedInfo outInfo = new PackageRemovedInfo(); synchronized (mInstallLock) { - boolean res = deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA, - outInfo, false); + boolean res = deletePackageLI(pkgName, null, false, + PackageManager.DELETE_KEEP_DATA, outInfo, false); if (res) { pkgList.add(pkgName); } else { diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java index 56f2166..6d31f0e 100644 --- a/services/java/com/android/server/pm/PackageSettingBase.java +++ b/services/java/com/android/server/pm/PackageSettingBase.java @@ -20,11 +20,13 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; +import android.content.pm.PackageUserState; +import android.content.pm.UserInfo; import android.util.SparseArray; -import android.util.SparseIntArray; import java.io.File; import java.util.HashSet; +import java.util.List; /** * Settings base class for pending and resolved classes. @@ -62,19 +64,11 @@ class PackageSettingBase extends GrantedPermissions { boolean permissionsFixed; boolean haveGids; + private static final PackageUserState DEFAULT_USER_STATE = new PackageUserState(); + // Whether this package is currently stopped, thus can not be // started until explicitly launched by the user. - private SparseArray<Boolean> stopped = new SparseArray<Boolean>(); - - // Set to true if we have never launched this app. - private SparseArray<Boolean> notLaunched = new SparseArray<Boolean>(); - - /* Explicitly disabled components */ - private SparseArray<HashSet<String>> disabledComponents = new SparseArray<HashSet<String>>(); - /* Explicitly enabled components */ - private SparseArray<HashSet<String>> enabledComponents = new SparseArray<HashSet<String>>(); - /* Enabled state */ - private SparseIntArray enabled = new SparseIntArray(); + private final SparseArray<PackageUserState> userState = new SparseArray<PackageUserState>(); int installStatus = PKG_INSTALL_COMPLETE; @@ -115,12 +109,11 @@ class PackageSettingBase extends GrantedPermissions { permissionsFixed = base.permissionsFixed; haveGids = base.haveGids; - notLaunched = base.notLaunched; - - disabledComponents = (SparseArray<HashSet<String>>) base.disabledComponents.clone(); - enabledComponents = (SparseArray<HashSet<String>>) base.enabledComponents.clone(); - enabled = (SparseIntArray) base.enabled.clone(); - stopped = (SparseArray<Boolean>) base.stopped.clone(); + userState.clear(); + for (int i=0; i<base.userState.size(); i++) { + userState.put(base.userState.keyAt(i), + new PackageUserState(base.userState.valueAt(i))); + } installStatus = base.installStatus; origPackage = base.origPackage; @@ -171,103 +164,174 @@ class PackageSettingBase extends GrantedPermissions { signatures = base.signatures; permissionsFixed = base.permissionsFixed; haveGids = base.haveGids; - stopped = base.stopped; - notLaunched = base.notLaunched; - disabledComponents = base.disabledComponents; - enabledComponents = base.enabledComponents; - enabled = base.enabled; + userState.clear(); + for (int i=0; i<base.userState.size(); i++) { + userState.put(base.userState.keyAt(i), base.userState.valueAt(i)); + } installStatus = base.installStatus; } + private PackageUserState modifyUserState(int userId) { + PackageUserState state = userState.get(userId); + if (state == null) { + state = new PackageUserState(); + userState.put(userId, state); + } + return state; + } + + public PackageUserState readUserState(int userId) { + PackageUserState state = userState.get(userId); + return state != null ? state : DEFAULT_USER_STATE; + } + void setEnabled(int state, int userId) { - enabled.put(userId, state); + modifyUserState(userId).enabled = state; } int getEnabled(int userId) { - return enabled.get(userId, COMPONENT_ENABLED_STATE_DEFAULT); + return readUserState(userId).enabled; + } + + void setInstalled(boolean inst, int userId) { + modifyUserState(userId).installed = inst; + } + + boolean getInstalled(int userId) { + return readUserState(userId).installed; + } + + boolean isAnyInstalled(int[] users) { + for (int user: users) { + if (readUserState(user).installed) { + return true; + } + } + return false; + } + + int[] getInstalledUsers(int[] users) { + int num = 0; + for (int user : users) { + if (getInstalled(user)) { + num++; + } + } + int[] res = new int[num]; + num = 0; + for (int user : users) { + if (getInstalled(user)) { + res[num] = user; + num++; + } + } + return res; } boolean getStopped(int userId) { - return stopped.get(userId, false); + return readUserState(userId).stopped; } void setStopped(boolean stop, int userId) { - stopped.put(userId, stop); + modifyUserState(userId).stopped = stop; } boolean getNotLaunched(int userId) { - return notLaunched.get(userId, false); + return readUserState(userId).notLaunched; } void setNotLaunched(boolean stop, int userId) { - notLaunched.put(userId, stop); + modifyUserState(userId).notLaunched = stop; + } + + void setUserState(int userId, int enabled, boolean installed, boolean stopped, + boolean notLaunched, HashSet<String> enabledComponents, + HashSet<String> disabledComponents) { + PackageUserState state = modifyUserState(userId); + state.enabled = enabled; + state.installed = installed; + state.stopped = stopped; + state.notLaunched = notLaunched; + state.enabledComponents = enabledComponents; + state.disabledComponents = disabledComponents; } HashSet<String> getEnabledComponents(int userId) { - return getComponentHashSet(enabledComponents, userId); + return readUserState(userId).enabledComponents; } HashSet<String> getDisabledComponents(int userId) { - return getComponentHashSet(disabledComponents, userId); + return readUserState(userId).disabledComponents; } void setEnabledComponents(HashSet<String> components, int userId) { - enabledComponents.put(userId, components); + modifyUserState(userId).enabledComponents = components; } void setDisabledComponents(HashSet<String> components, int userId) { - disabledComponents.put(userId, components); + modifyUserState(userId).disabledComponents = components; + } + + void setEnabledComponentsCopy(HashSet<String> components, int userId) { + modifyUserState(userId).enabledComponents = components != null + ? new HashSet<String>(components) : null; } - private HashSet<String> getComponentHashSet(SparseArray<HashSet<String>> setArray, int userId) { - HashSet<String> set = setArray.get(userId); - if (set == null) { - set = new HashSet<String>(1); - setArray.put(userId, set); + void setDisabledComponentsCopy(HashSet<String> components, int userId) { + modifyUserState(userId).disabledComponents = components != null + ? new HashSet<String>(components) : null; + } + + PackageUserState modifyUserStateComponents(int userId, boolean disabled, boolean enabled) { + PackageUserState state = modifyUserState(userId); + if (disabled && state.disabledComponents == null) { + state.disabledComponents = new HashSet<String>(1); + } + if (enabled && state.enabledComponents == null) { + state.enabledComponents = new HashSet<String>(1); } - return set; + return state; } void addDisabledComponent(String componentClassName, int userId) { - HashSet<String> disabled = getComponentHashSet(disabledComponents, userId); - disabled.add(componentClassName); + modifyUserStateComponents(userId, true, false).disabledComponents.add(componentClassName); } void addEnabledComponent(String componentClassName, int userId) { - HashSet<String> enabled = getComponentHashSet(enabledComponents, userId); - enabled.add(componentClassName); + modifyUserStateComponents(userId, false, true).enabledComponents.add(componentClassName); } boolean enableComponentLPw(String componentClassName, int userId) { - HashSet<String> disabled = getComponentHashSet(disabledComponents, userId); - HashSet<String> enabled = getComponentHashSet(enabledComponents, userId); - boolean changed = disabled.remove(componentClassName); - changed |= enabled.add(componentClassName); + PackageUserState state = modifyUserStateComponents(userId, false, true); + boolean changed = state.disabledComponents != null + ? state.disabledComponents.remove(componentClassName) : false; + changed |= state.enabledComponents.add(componentClassName); return changed; } boolean disableComponentLPw(String componentClassName, int userId) { - HashSet<String> disabled = getComponentHashSet(disabledComponents, userId); - HashSet<String> enabled = getComponentHashSet(enabledComponents, userId); - boolean changed = enabled.remove(componentClassName); - changed |= disabled.add(componentClassName); + PackageUserState state = modifyUserStateComponents(userId, true, false); + boolean changed = state.enabledComponents != null + ? state.enabledComponents.remove(componentClassName) : false; + changed |= state.disabledComponents.add(componentClassName); return changed; } boolean restoreComponentLPw(String componentClassName, int userId) { - HashSet<String> disabled = getComponentHashSet(disabledComponents, userId); - HashSet<String> enabled = getComponentHashSet(enabledComponents, userId); - boolean changed = enabled.remove(componentClassName); - changed |= disabled.remove(componentClassName); + PackageUserState state = modifyUserStateComponents(userId, true, true); + boolean changed = state.disabledComponents != null + ? state.disabledComponents.remove(componentClassName) : false; + changed |= state.enabledComponents != null + ? state.enabledComponents.remove(componentClassName) : false; return changed; } int getCurrentEnabledStateLPr(String componentName, int userId) { - HashSet<String> disabled = getComponentHashSet(disabledComponents, userId); - HashSet<String> enabled = getComponentHashSet(enabledComponents, userId); - if (enabled.contains(componentName)) { + PackageUserState state = readUserState(userId); + if (state.enabledComponents != null && state.enabledComponents.contains(componentName)) { return COMPONENT_ENABLED_STATE_ENABLED; - } else if (disabled.contains(componentName)) { + } else if (state.disabledComponents != null + && state.disabledComponents.contains(componentName)) { return COMPONENT_ENABLED_STATE_DISABLED; } else { return COMPONENT_ENABLED_STATE_DEFAULT; @@ -275,11 +339,6 @@ class PackageSettingBase extends GrantedPermissions { } void removeUser(int userId) { - enabled.delete(userId); - stopped.delete(userId); - enabledComponents.delete(userId); - disabledComponents.delete(userId); - notLaunched.delete(userId); + userState.delete(userId); } - } diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index cfc0f5c..a341304 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -38,11 +38,13 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.ComponentInfo; +import android.content.pm.PackageCleanItem; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PermissionInfo; import android.content.pm.Signature; import android.content.pm.UserInfo; +import android.content.pm.PackageUserState; import android.content.pm.VerifierDeviceIdentity; import android.os.Binder; import android.os.Environment; @@ -92,9 +94,12 @@ final class Settings { private static final String TAG_PACKAGE = "pkg"; private static final String ATTR_NAME = "name"; + private static final String ATTR_USER = "user"; + private static final String ATTR_CODE = "code"; private static final String ATTR_NOT_LAUNCHED = "nl"; private static final String ATTR_ENABLED = "enabled"; private static final String ATTR_STOPPED = "stopped"; + private static final String ATTR_INSTALLED = "inst"; private final File mSettingsFilename; private final File mBackupSettingsFilename; @@ -156,7 +161,8 @@ final class Settings { // Packages that have been uninstalled and still need their external // storage data deleted. - final ArrayList<String> mPackagesToBeCleaned = new ArrayList<String>(); + final SparseArray<ArrayList<PackageCleanItem>> mPackagesToBeCleaned + = new SparseArray<ArrayList<PackageCleanItem>>(); // Packages that have been renamed since they were first installed. // Keys are the new names of the packages, values are the original @@ -200,10 +206,11 @@ final class Settings { PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage, String realName, SharedUserSetting sharedUser, File codePath, File resourcePath, - String nativeLibraryPathString, int pkgFlags, boolean create, boolean add) { + String nativeLibraryPathString, int pkgFlags, UserHandle user, boolean add) { final String name = pkg.packageName; PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath, - resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags, create, add); + resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags, + user, add); return p; } @@ -364,7 +371,8 @@ final class Settings { private PackageSetting getPackageLPw(String name, PackageSetting origPackage, String realName, SharedUserSetting sharedUser, File codePath, File resourcePath, - String nativeLibraryPathString, int vc, int pkgFlags, boolean create, boolean add) { + String nativeLibraryPathString, int vc, int pkgFlags, + UserHandle installUser, boolean add) { PackageSetting p = mPackages.get(name); if (p != null) { if (!p.codePath.equals(codePath)) { @@ -407,11 +415,6 @@ final class Settings { } } if (p == null) { - // Create a new PackageSettings entry. this can end up here because - // of code path mismatch or user id mismatch of an updated system partition - if (!create) { - return null; - } if (origPackage != null) { // We are consuming the data from an existing package. p = new PackageSetting(origPackage.name, name, codePath, resourcePath, @@ -445,8 +448,20 @@ final class Settings { List<UserInfo> users = getAllUsers(); if (users != null) { for (UserInfo user : users) { - p.setStopped(true, user.id); - p.setNotLaunched(true, user.id); + // By default we consider this app to be installed + // for the user if no user has been specified (which + // means to leave it at its original value, and the + // original default value is true), or we are being + // asked to install for all users, or this is the + // user we are installing for. + final boolean installed = installUser == null + || installUser.getIdentifier() == UserHandle.USER_ALL + || installUser.getIdentifier() == user.id; + p.setUserState(user.id, COMPONENT_ENABLED_STATE_DEFAULT, + installed, + true, // stopped, + true, // notLaunched + null, null); writePackageRestrictionsLPr(user.id); } } @@ -472,12 +487,10 @@ final class Settings { if (users != null) { for (UserInfo user : users) { int userId = user.id; - p.setDisabledComponents( - new HashSet<String>(dis.getDisabledComponents(userId)), - userId); - p.setEnabledComponents( - new HashSet<String>(dis.getEnabledComponents(userId)), - userId); + p.setDisabledComponentsCopy( + dis.getDisabledComponents(userId), userId); + p.setEnabledComponentsCopy( + dis.getEnabledComponents(userId), userId); } } // Add new setting to list of user ids @@ -498,6 +511,25 @@ final class Settings { // user preferences addPackageSettingLPw(p, name, sharedUser); } + } else { + if (installUser != null) { + // The caller has explicitly specified the user they want this + // package installed for, and the package already exists. + // Make sure it conforms to the new request. + List<UserInfo> users = getAllUsers(); + if (users != null) { + for (UserInfo user : users) { + if (installUser.getIdentifier() == UserHandle.USER_ALL + || installUser.getIdentifier() == user.id) { + boolean installed = p.getInstalled(user.id); + if (!installed) { + p.setInstalled(true, user.id); + writePackageRestrictionsLPr(user.id); + } + } + } + } + } } return p; } @@ -778,10 +810,14 @@ final class Settings { + "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. + // in the stopped state, but not at first boot. Also + // consider all applications to be installed. for (PackageSetting pkg : mPackages.values()) { - pkg.setStopped(false, userId); - pkg.setNotLaunched(false, userId); + pkg.setUserState(userId, COMPONENT_ENABLED_STATE_DEFAULT, + true, // installed + false, // stopped + false, // notLaunched + null, null); } return; } @@ -823,17 +859,21 @@ final class Settings { XmlUtils.skipCurrentTag(parser); continue; } - String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED); - int enabled = enabledStr == null ? COMPONENT_ENABLED_STATE_DEFAULT - : Integer.parseInt(enabledStr); - ps.setEnabled(enabled, userId); - String stoppedStr = parser.getAttributeValue(null, ATTR_STOPPED); - boolean stopped = stoppedStr == null ? false : Boolean.parseBoolean(stoppedStr); - ps.setStopped(stopped, userId); - String notLaunchedStr = parser.getAttributeValue(null, ATTR_NOT_LAUNCHED); - boolean notLaunched = stoppedStr == null ? false - : Boolean.parseBoolean(notLaunchedStr); - ps.setNotLaunched(notLaunched, userId); + final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED); + final int enabled = enabledStr == null + ? COMPONENT_ENABLED_STATE_DEFAULT : Integer.parseInt(enabledStr); + final String installedStr = parser.getAttributeValue(null, ATTR_INSTALLED); + final boolean installed = installedStr == null + ? true : Boolean.parseBoolean(installedStr); + final String stoppedStr = parser.getAttributeValue(null, ATTR_STOPPED); + final boolean stopped = stoppedStr == null + ? false : Boolean.parseBoolean(stoppedStr); + final String notLaunchedStr = parser.getAttributeValue(null, ATTR_NOT_LAUNCHED); + final boolean notLaunched = stoppedStr == null + ? false : Boolean.parseBoolean(notLaunchedStr); + + HashSet<String> enabledComponents = null; + HashSet<String> disabledComponents = null; int packageDepth = parser.getDepth(); while ((type=parser.next()) != XmlPullParser.END_DOCUMENT @@ -845,13 +885,14 @@ final class Settings { } tagName = parser.getName(); if (tagName.equals(TAG_ENABLED_COMPONENTS)) { - HashSet<String> components = readComponentsLPr(parser); - ps.setEnabledComponents(components, userId); + enabledComponents = readComponentsLPr(parser); } else if (tagName.equals(TAG_DISABLED_COMPONENTS)) { - HashSet<String> components = readComponentsLPr(parser); - ps.setDisabledComponents(components, userId); + disabledComponents = readComponentsLPr(parser); } } + + ps.setUserState(userId, enabled, installed, stopped, notLaunched, + enabledComponents, disabledComponents); } else { Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: " + parser.getName()); @@ -876,7 +917,7 @@ final class Settings { private HashSet<String> readComponentsLPr(XmlPullParser parser) throws IOException, XmlPullParserException { - HashSet<String> components = new HashSet<String>(); + HashSet<String> components = null; int type; int outerDepth = parser.getDepth(); String tagName; @@ -891,6 +932,9 @@ final class Settings { if (tagName.equals(TAG_ITEM)) { String componentName = parser.getAttributeValue(null, ATTR_NAME); if (componentName != null) { + if (components == null) { + components = new HashSet<String>(); + } components.add(componentName); } } @@ -936,41 +980,44 @@ final class Settings { serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS); for (final PackageSetting pkg : mPackages.values()) { - if (pkg.getStopped(userId) - || pkg.getNotLaunched(userId) - || pkg.getEnabled(userId) != COMPONENT_ENABLED_STATE_DEFAULT - || pkg.getEnabledComponents(userId).size() > 0 - || pkg.getDisabledComponents(userId).size() > 0) { + PackageUserState ustate = pkg.readUserState(userId); + if (ustate.stopped || ustate.notLaunched || !ustate.installed + || ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT + || (ustate.enabledComponents != null + && ustate.enabledComponents.size() > 0) + || (ustate.disabledComponents != null + && ustate.disabledComponents.size() > 0)) { serializer.startTag(null, TAG_PACKAGE); serializer.attribute(null, ATTR_NAME, pkg.name); - boolean stopped = pkg.getStopped(userId); - boolean notLaunched = pkg.getNotLaunched(userId); - int enabled = pkg.getEnabled(userId); - if (DEBUG_MU) Log.i(TAG, " pkg=" + pkg.name + ", state=" + enabled); - HashSet<String> enabledComponents = pkg.getEnabledComponents(userId); - HashSet<String> disabledComponents = pkg.getDisabledComponents(userId); - - if (stopped) { + if (DEBUG_MU) Log.i(TAG, " pkg=" + pkg.name + ", state=" + ustate.enabled); + + if (!ustate.installed) { + serializer.attribute(null, ATTR_INSTALLED, "false"); + } + if (ustate.stopped) { serializer.attribute(null, ATTR_STOPPED, "true"); } - if (notLaunched) { + if (ustate.notLaunched) { serializer.attribute(null, ATTR_NOT_LAUNCHED, "true"); } - if (enabled != COMPONENT_ENABLED_STATE_DEFAULT) { - serializer.attribute(null, ATTR_ENABLED, Integer.toString(enabled)); + if (ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT) { + serializer.attribute(null, ATTR_ENABLED, + Integer.toString(ustate.enabled)); } - if (enabledComponents.size() > 0) { + if (ustate.enabledComponents != null + && ustate.enabledComponents.size() > 0) { serializer.startTag(null, TAG_ENABLED_COMPONENTS); - for (final String name : enabledComponents) { + for (final String name : ustate.enabledComponents) { serializer.startTag(null, TAG_ITEM); serializer.attribute(null, ATTR_NAME, name); serializer.endTag(null, TAG_ITEM); } serializer.endTag(null, TAG_ENABLED_COMPONENTS); } - if (disabledComponents.size() > 0) { + if (ustate.disabledComponents != null + && ustate.disabledComponents.size() > 0) { serializer.startTag(null, TAG_DISABLED_COMPONENTS); - for (final String name : disabledComponents) { + for (final String name : ustate.disabledComponents) { serializer.startTag(null, TAG_ITEM); serializer.attribute(null, ATTR_NAME, name); serializer.endTag(null, TAG_ITEM); @@ -1210,9 +1257,17 @@ final class Settings { if (mPackagesToBeCleaned.size() > 0) { for (int i=0; i<mPackagesToBeCleaned.size(); i++) { - serializer.startTag(null, "cleaning-package"); - serializer.attribute(null, ATTR_NAME, mPackagesToBeCleaned.get(i)); - serializer.endTag(null, "cleaning-package"); + final int userId = mPackagesToBeCleaned.keyAt(i); + final String userStr = Integer.toString(userId); + final ArrayList<PackageCleanItem> pkgs = mPackagesToBeCleaned.valueAt(i); + for (int j=0; j<pkgs.size(); j++) { + serializer.startTag(null, "cleaning-package"); + PackageCleanItem item = pkgs.get(i); + serializer.attribute(null, ATTR_NAME, item.packageName); + serializer.attribute(null, ATTR_CODE, item.andCode ? "true" : "false"); + serializer.attribute(null, ATTR_USER, userStr); + serializer.endTag(null, "cleaning-package"); + } } } @@ -1468,6 +1523,17 @@ final class Settings { return ret; } + void addPackageToCleanLPw(int userId, PackageCleanItem pkg) { + ArrayList<PackageCleanItem> pkgs = mPackagesToBeCleaned.get(userId); + if (pkgs == null) { + pkgs = new ArrayList<PackageCleanItem>(); + mPackagesToBeCleaned.put(userId, pkgs); + } + if (!pkgs.contains(pkg)) { + pkgs.add(pkg); + } + } + boolean readLPw(List<UserInfo> users) { FileInputStream str = null; if (mBackupSettingsFilename.exists()) { @@ -1545,8 +1611,21 @@ final class Settings { readDisabledSysPackageLPw(parser); } else if (tagName.equals("cleaning-package")) { String name = parser.getAttributeValue(null, ATTR_NAME); + String userStr = parser.getAttributeValue(null, ATTR_USER); + String codeStr = parser.getAttributeValue(null, ATTR_CODE); if (name != null) { - mPackagesToBeCleaned.add(name); + int user = 0; + boolean andCode = true; + try { + if (userStr != null) { + user = Integer.parseInt(userStr); + } + } catch (NumberFormatException e) { + } + if (codeStr != null) { + andCode = Boolean.parseBoolean(codeStr); + } + addPackageToCleanLPw(user, new PackageCleanItem(name, andCode)); } } else if (tagName.equals("renamed-package")) { String nname = parser.getAttributeValue(null, "new"); @@ -1623,7 +1702,8 @@ final class Settings { if (idObj != null && idObj instanceof SharedUserSetting) { PackageSetting p = getPackageLPw(pp.name, null, pp.realName, (SharedUserSetting) idObj, pp.codePath, pp.resourcePath, - pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags, true, true); + pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags, + UserHandle.ALL, true); if (p == null) { PackageManagerService.reportSettingsProblem(Log.WARN, "Unable to create application package for " + pp.name); @@ -2292,6 +2372,10 @@ final class Settings { return ps; } + private String compToString(HashSet<String> cmp) { + return cmp != null ? Arrays.toString(cmp.toArray()) : "[]"; + } + boolean isEnabledLPr(ComponentInfo componentInfo, int flags, int userId) { if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { return true; @@ -2302,24 +2386,26 @@ final class Settings { Log.v(PackageManagerService.TAG, "isEnabledLock - packageName = " + componentInfo.packageName + " componentName = " + componentInfo.name); Log.v(PackageManagerService.TAG, "enabledComponents: " - + Arrays.toString(packageSettings.getEnabledComponents(userId).toArray())); + + compToString(packageSettings.getEnabledComponents(userId))); Log.v(PackageManagerService.TAG, "disabledComponents: " - + Arrays.toString(packageSettings.getDisabledComponents(userId).toArray())); + + compToString(packageSettings.getDisabledComponents(userId))); } if (packageSettings == null) { return false; } - final int enabled = packageSettings.getEnabled(userId); - if (enabled == COMPONENT_ENABLED_STATE_DISABLED - || enabled == COMPONENT_ENABLED_STATE_DISABLED_USER + PackageUserState ustate = packageSettings.readUserState(userId); + if (ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED + || ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED_USER || (packageSettings.pkg != null && !packageSettings.pkg.applicationInfo.enabled - && enabled == COMPONENT_ENABLED_STATE_DEFAULT)) { + && ustate.enabled == COMPONENT_ENABLED_STATE_DEFAULT)) { return false; } - if (packageSettings.getEnabledComponents(userId).contains(componentInfo.name)) { + if (ustate.enabledComponents != null + && ustate.enabledComponents.contains(componentInfo.name)) { return true; } - if (packageSettings.getDisabledComponents(userId).contains(componentInfo.name)) { + if (ustate.disabledComponents != null + && ustate.disabledComponents.contains(componentInfo.name)) { return false; } return componentInfo.enabled; @@ -2378,7 +2464,7 @@ final class Settings { if (pkgSetting.installerPackageName != null) { PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgSetting.name, null, - pkgSetting.installerPackageName, null, userId); + pkgSetting.installerPackageName, null, new int[] {userId}); } pkgSetting.setNotLaunched(false, userId); } @@ -2427,7 +2513,6 @@ final class Settings { ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION", ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE", ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP", - ApplicationInfo.FLAG_STOPPED, "STOPPED", ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK", ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE", }; @@ -2537,22 +2622,28 @@ final class Settings { 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(" installStatus="); pw.println(ps.installStatus); for (UserInfo user : users) { - pw.print(" User "); pw.print(user.id); pw.print(": "); + pw.print(" User "); pw.print(user.id); pw.print(": "); + pw.print(" installed="); + pw.print(ps.getInstalled(user.id)); pw.print(" stopped="); pw.print(ps.getStopped(user.id)); + pw.print(" notLaunched="); + pw.print(ps.getNotLaunched(user.id)); pw.print(" enabled="); pw.println(ps.getEnabled(user.id)); - if (ps.getDisabledComponents(user.id).size() > 0) { - pw.println(" disabledComponents:"); - for (String s : ps.getDisabledComponents(user.id)) { + HashSet<String> cmp = ps.getDisabledComponents(user.id); + if (cmp != null && cmp.size() > 0) { + pw.println(" disabledComponents:"); + for (String s : cmp) { pw.print(" "); pw.println(s); } } - if (ps.getEnabledComponents(user.id).size() > 0) { - pw.println(" enabledComponents:"); - for (String s : ps.getEnabledComponents(user.id)) { + cmp = ps.getEnabledComponents(user.id); + if (cmp != null && cmp.size() > 0) { + pw.println(" enabledComponents:"); + for (String s : cmp) { pw.print(" "); pw.println(s); } } diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java index 6a76c5d..8899ea2 100644 --- a/services/java/com/android/server/pm/UserManagerService.java +++ b/services/java/com/android/server/pm/UserManagerService.java @@ -262,7 +262,9 @@ public class UserManagerService extends IUserManager.Stub { * @return the array of user ids. */ int[] getUserIds() { - return mUserIds; + synchronized (mUsers) { + return mUserIds; + } } private void readUserList() { @@ -611,12 +613,11 @@ public class UserManagerService extends IUserManager.Stub { * Caches the list of user ids in an array, adjusting the array size when necessary. */ private void updateUserIdsLocked() { - if (mUserIds == null || mUserIds.length != mUsers.size()) { - mUserIds = new int[mUsers.size()]; - } + int[] newUsers = new int[mUsers.size()]; for (int i = 0; i < mUsers.size(); i++) { - mUserIds[i] = mUsers.keyAt(i); + newUsers[i] = mUsers.keyAt(i); } + mUserIds = newUsers; } /** diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java index 12ad4fe..6047cda 100644 --- a/test-runner/src/android/test/mock/MockContext.java +++ b/test-runner/src/android/test/mock/MockContext.java @@ -360,6 +360,18 @@ public class MockContext extends Context { throw new UnsupportedOperationException(); } + /** @hide */ + @Override + public ComponentName startServiceAsUser(Intent service, UserHandle user) { + throw new UnsupportedOperationException(); + } + + /** @hide */ + @Override + public boolean stopServiceAsUser(Intent service, UserHandle user) { + throw new UnsupportedOperationException(); + } + @Override public boolean bindService(Intent service, ServiceConnection conn, int flags) { throw new UnsupportedOperationException(); diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index ac40fc6b..562f286 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -41,6 +41,7 @@ import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.content.pm.VerificationParams; import android.content.pm.VerifierDeviceIdentity; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; @@ -531,6 +532,15 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + /** + * @hide + */ + @Override + public int installExistingPackage(String packageName) + throws NameNotFoundException { + throw new UnsupportedOperationException(); + } + @Override public void verifyPendingInstall(int id, int verificationCode) { throw new UnsupportedOperationException(); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 3d45bff..76033d4 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -1281,6 +1281,18 @@ public final class BridgeContext extends Context { } @Override + public ComponentName startServiceAsUser(Intent arg0, UserHandle arg1) { + // pass + return null; + } + + @Override + public boolean stopServiceAsUser(Intent arg0, UserHandle arg1) { + // pass + return false; + } + + @Override public void unbindService(ServiceConnection arg0) { // pass |