summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/pm
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/pm')
-rw-r--r--services/java/com/android/server/pm/Installer.java44
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java1878
-rw-r--r--services/java/com/android/server/pm/PackageSettingBase.java189
-rw-r--r--services/java/com/android/server/pm/PackageVerificationState.java21
-rw-r--r--services/java/com/android/server/pm/PreferredActivity.java18
-rw-r--r--services/java/com/android/server/pm/Settings.java330
-rw-r--r--services/java/com/android/server/pm/ShutdownThread.java521
-rw-r--r--services/java/com/android/server/pm/UserManager.java465
-rw-r--r--services/java/com/android/server/pm/UserManagerService.java723
9 files changed, 2350 insertions, 1839 deletions
diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java
index 48004bb..ad85c0d 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -25,7 +25,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-class Installer {
+public final class Installer {
private static final String TAG = "Installer";
private static final boolean LOCAL_DEBUG = false;
@@ -324,26 +324,14 @@ class Installer {
return execute(builder.toString());
}
- /*
- * @param packagePathSuffix The name of the path relative to install
- * directory. Say if the path name is /data/app/com.test-1.apk, the package
- * suffix path will be com.test-1
- */
- public int setForwardLockPerm(String packagePathSuffix, int gid) {
- StringBuilder builder = new StringBuilder("protect");
- builder.append(' ');
- builder.append(packagePathSuffix);
- builder.append(' ');
- builder.append(gid);
- return execute(builder.toString());
- }
-
- public int getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath,
+ public int getSizeInfo(String pkgName, int persona, String apkPath, String fwdLockApkPath,
String asecPath, PackageStats pStats) {
StringBuilder builder = new StringBuilder("getsize");
builder.append(' ');
builder.append(pkgName);
builder.append(' ');
+ builder.append(persona);
+ builder.append(' ');
builder.append(apkPath);
builder.append(' ');
builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
@@ -371,12 +359,20 @@ class Installer {
return execute("movefiles");
}
+ /**
+ * Links the native library directory in an application's directory to its
+ * real location.
+ *
+ * @param dataPath data directory where the application is
+ * @param nativeLibPath target native library path
+ * @return -1 on error
+ */
public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath) {
if (dataPath == null) {
- Slog.e(TAG, "unlinkNativeLibraryDirectory dataPath is null");
+ Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null");
return -1;
} else if (nativeLibPath == null) {
- Slog.e(TAG, "unlinkNativeLibraryDirectory nativeLibPath is null");
+ Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null");
return -1;
}
@@ -387,16 +383,4 @@ class Installer {
return execute(builder.toString());
}
-
- public int unlinkNativeLibraryDirectory(String dataPath) {
- if (dataPath == null) {
- Slog.e(TAG, "unlinkNativeLibraryDirectory dataPath is null");
- return -1;
- }
-
- StringBuilder builder = new StringBuilder("unlinklib ");
- builder.append(dataPath);
-
- return execute(builder.toString());
- }
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index f914271..536c612 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -25,6 +25,11 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.ArrayUtils.removeInt;
import static libcore.io.OsConstants.S_ISLNK;
+import static libcore.io.OsConstants.S_IRWXU;
+import static libcore.io.OsConstants.S_IRGRP;
+import static libcore.io.OsConstants.S_IXGRP;
+import static libcore.io.OsConstants.S_IROTH;
+import static libcore.io.OsConstants.S_IXOTH;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
@@ -64,10 +69,13 @@ 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.PackageUserState;
+import android.content.pm.PackageParser.ActivityIntentInfo;
import android.content.pm.PackageStats;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
@@ -76,8 +84,8 @@ import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
-import android.content.pm.UserInfo;
import android.content.pm.ManifestDigest;
+import android.content.pm.VerificationParams;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VerifierInfo;
import android.net.Uri;
@@ -100,7 +108,8 @@ import android.os.SELinux;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.os.UserId;
+import android.os.UserHandle;
+import android.os.Environment.UserEnvironment;
import android.provider.Settings.Secure;
import android.security.SystemKeyStore;
import android.util.DisplayMetrics;
@@ -144,6 +153,7 @@ import java.util.Set;
import libcore.io.ErrnoException;
import libcore.io.IoUtils;
import libcore.io.Libcore;
+import libcore.io.OsConstants;
import libcore.io.StructStat;
/**
@@ -165,6 +175,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;
@@ -175,6 +186,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
private static final int NFC_UID = Process.NFC_UID;
+ private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID;
private static final boolean GET_CERTIFICATES = true;
@@ -203,14 +215,21 @@ public class PackageManagerService extends IPackageManager.Stub {
/**
* Whether verification is enabled by default.
*/
- // STOPSHIP: change this to true
- private static final boolean DEFAULT_VERIFY_ENABLE = false;
+ private static final boolean DEFAULT_VERIFY_ENABLE = true;
/**
* The default maximum time to wait for the verification agent to return in
* milliseconds.
*/
- private static final long DEFAULT_VERIFICATION_TIMEOUT = 60 * 1000;
+ private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
+
+ /**
+ * The default response for package verification timeout.
+ *
+ * This can be either PackageManager.VERIFICATION_ALLOW or
+ * PackageManager.VERIFICATION_REJECT.
+ */
+ private static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW;
static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
@@ -264,7 +283,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// This is the object monitoring mDrmAppPrivateInstallDir.
final FileObserver mDrmAppInstallObserver;
- // Used for priviledge escalation. MUST NOT BE CALLED WITH mPackages
+ // Used for privilege escalation. MUST NOT BE CALLED WITH mPackages
// LOCK HELD. Can be called with mInstallLock held.
final Installer mInstaller;
@@ -274,6 +293,12 @@ public class PackageManagerService extends IPackageManager.Stub {
final File mAppInstallDir;
final File mDalvikCacheDir;
+ /**
+ * Directory to which applications installed internally have native
+ * libraries copied.
+ */
+ private File mAppLibInstallDir;
+
// Directory containing the private parts (e.g. code and non-resource assets) of forward-locked
// apps.
final File mDrmAppPrivateInstallDir;
@@ -388,6 +413,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// package uri's from external media onto secure containers
// or internal storage.
private IMediaContainerService mContainerService = null;
+ private int mContainerServiceUserId;
static final int SEND_PENDING_BROADCAST = 1;
static final int MCS_BOUND = 3;
@@ -410,7 +436,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// Delay time in millisecs
static final int BROADCAST_DELAY = 10 * 1000;
- static UserManager sUserManager;
+ static UserManagerService sUserManager;
// Stores a list of users whose package restrictions file needs to be updated
private HashSet<Integer> mDirtyUsers = new HashSet<Integer>();
@@ -456,8 +482,15 @@ public class PackageManagerService extends IPackageManager.Stub {
" DefaultContainerService");
Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ mContainerServiceUserId = 0;
+ if (mPendingInstalls.size() > 0) {
+ mContainerServiceUserId = mPendingInstalls.get(0).getUser().getIdentifier();
+ if (mContainerServiceUserId == UserHandle.USER_ALL) {
+ mContainerServiceUserId = 0;
+ }
+ }
if (mContext.bindService(service, mDefContainerConn,
- Context.BIND_AUTO_CREATE)) {
+ Context.BIND_AUTO_CREATE, mContainerServiceUserId)) {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
mBound = true;
return true;
@@ -534,6 +567,15 @@ public class PackageManagerService extends IPackageManager.Stub {
} else if (mPendingInstalls.size() > 0) {
HandlerParams params = mPendingInstalls.get(0);
if (params != null) {
+ // Check if we're connected to the correct service, if it's an install
+ // request.
+ final int installFor = params.getUser().getIdentifier();
+ if (installFor != mContainerServiceUserId
+ && (installFor == UserHandle.USER_ALL
+ && mContainerServiceUserId != 0)) {
+ mHandler.sendEmptyMessage(MCS_RECONNECT);
+ return;
+ }
if (params.startCopy()) {
// We are done... look for more work or to
// go idle.
@@ -650,15 +692,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);
@@ -674,26 +722,65 @@ public class PackageManagerService extends IPackageManager.Stub {
res.removedInfo.sendBroadcast(false, true);
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, res.uid);
+ // Determine the set of users who are adding this
+ // package for the first time vs. those who are seeing
+ // an update.
+ int[] firstUsers;
+ int[] updateUsers = new int[0];
+ if (res.origUsers == null || res.origUsers.length == 0) {
+ firstUsers = res.newUsers;
+ } else {
+ firstUsers = new int[0];
+ for (int i=0; i<res.newUsers.length; i++) {
+ int user = res.newUsers[i];
+ boolean isNew = true;
+ for (int j=0; j<res.origUsers.length; j++) {
+ if (res.origUsers[j] == user) {
+ isNew = false;
+ break;
+ }
+ }
+ if (isNew) {
+ int[] newFirst = new int[firstUsers.length+1];
+ System.arraycopy(firstUsers, 0, newFirst, 0,
+ firstUsers.length);
+ newFirst[firstUsers.length] = user;
+ firstUsers = newFirst;
+ } else {
+ int[] newUpdate = new int[updateUsers.length+1];
+ System.arraycopy(updateUsers, 0, newUpdate, 0,
+ updateUsers.length);
+ newUpdate[updateUsers.length] = user;
+ updateUsers = newUpdate;
+ }
+ }
+ }
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
+ res.pkg.applicationInfo.packageName,
+ extras, null, null, firstUsers);
final boolean update = res.removedInfo.removedPackage != null;
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
res.pkg.applicationInfo.packageName,
- extras, null, null, UserId.USER_ALL);
+ extras, null, null, updateUsers);
if (update) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
res.pkg.applicationInfo.packageName,
- extras, null, null, UserId.USER_ALL);
+ extras, null, null, updateUsers);
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null, null,
- res.pkg.applicationInfo.packageName, null,
- UserId.USER_ALL);
+ res.pkg.applicationInfo.packageName, null, updateUsers);
}
if (res.removedInfo.args != null) {
// Remove the replaced package's older resources safely now
deleteOld = true;
}
+
+ // Log current value of "unknown sources" setting
+ EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
+ getUnknownSourcesSettings());
}
// Force a gc to clear up things
Runtime.getRuntime().gc();
@@ -764,17 +851,33 @@ public class PackageManagerService extends IPackageManager.Stub {
final int verificationId = msg.arg1;
final PackageVerificationState state = mPendingVerification.get(verificationId);
- if (state != null) {
+ if ((state != null) && !state.timeoutExtended()) {
final InstallArgs args = state.getInstallArgs();
Slog.i(TAG, "Verification timed out for " + args.packageURI.toString());
mPendingVerification.remove(verificationId);
- int ret = PackageManager.INSTALL_FAILED_VERIFICATION_TIMEOUT;
- processPendingInstall(args, ret);
+ int ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
+
+ if (getDefaultVerificationResponse() == PackageManager.VERIFICATION_ALLOW) {
+ Slog.i(TAG, "Continuing with installation of "
+ + args.packageURI.toString());
+ state.setVerifierResponse(Binder.getCallingUid(),
+ PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
+ broadcastPackageVerified(verificationId, args.packageURI,
+ PackageManager.VERIFICATION_ALLOW);
+ try {
+ ret = args.copyApk(mContainerService, true);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Could not contact the ContainerService");
+ }
+ } else {
+ broadcastPackageVerified(verificationId, args.packageURI,
+ PackageManager.VERIFICATION_REJECT);
+ }
+ processPendingInstall(args, ret);
mHandler.sendEmptyMessage(MCS_UNBIND);
}
-
break;
}
case PACKAGE_VERIFIED: {
@@ -798,6 +901,8 @@ public class PackageManagerService extends IPackageManager.Stub {
int ret;
if (state.isInstallAllowed()) {
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ broadcastPackageVerified(verificationId, args.packageURI,
+ response.code);
try {
ret = args.copyApk(mContainerService, true);
} catch (RemoteException e) {
@@ -832,9 +937,10 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- public static final IPackageManager main(Context context, boolean factoryTest,
- boolean onlyCore) {
- PackageManagerService m = new PackageManagerService(context, factoryTest, onlyCore);
+ public static final IPackageManager main(Context context, Installer installer,
+ boolean factoryTest, boolean onlyCore) {
+ PackageManagerService m = new PackageManagerService(context, installer,
+ factoryTest, onlyCore);
ServiceManager.addService("package", m);
return m;
}
@@ -861,7 +967,8 @@ public class PackageManagerService extends IPackageManager.Stub {
return res;
}
- public PackageManagerService(Context context, boolean factoryTest, boolean onlyCore) {
+ public PackageManagerService(Context context, Installer installer,
+ boolean factoryTest, boolean onlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
@@ -874,12 +981,13 @@ public class PackageManagerService extends IPackageManager.Stub {
mOnlyCore = onlyCore;
mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
- mSettings = new Settings();
+ mSettings = new Settings(context);
mSettings.addSharedUserLPw("android.uid.system",
Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM);
+ mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, ApplicationInfo.FLAG_SYSTEM);
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
@@ -898,7 +1006,7 @@ public class PackageManagerService extends IPackageManager.Stub {
mSeparateProcesses = null;
}
- mInstaller = new Installer();
+ mInstaller = installer;
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
@@ -916,11 +1024,12 @@ public class PackageManagerService extends IPackageManager.Stub {
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
- sUserManager = new UserManager(mInstaller, mUserAppDataDir);
+ sUserManager = new UserManagerService(context, this,
+ mInstallLock, mPackages);
readPermissions();
- mRestoredSettings = mSettings.readLPw(getUsers());
+ mRestoredSettings = mSettings.readLPw(sUserManager.getUsers());
long startTime = SystemClock.uptimeMillis();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
@@ -1099,7 +1208,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
Slog.i(TAG, "Expecting better updatd system app for " + ps.name
+ "; removing system app");
- removePackageLI(scannedPkg, true);
+ removePackageLI(ps, true);
}
continue;
@@ -1110,8 +1219,7 @@ public class PackageManagerService extends IPackageManager.Stub {
String msg = "System package " + ps.name
+ " no longer exists; wiping its data";
reportSettingsProblem(Log.WARN, msg);
- mInstaller.remove(ps.name, 0);
- sUserManager.removePackageForAllUsers(ps.name);
+ removeDataDirsLI(ps.name);
} else {
final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
@@ -1122,6 +1230,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
mAppInstallDir = new File(dataDir, "app");
+ mAppLibInstallDir = new File(dataDir, "app-lib");
//look for any incomplete package installations
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
//clean up list
@@ -1160,9 +1269,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (deletedPkg == null) {
msg = "Updated system package " + deletedAppName
+ " no longer exists; wiping its data";
-
- mInstaller.remove(deletedAppName, 0);
- sUserManager.removePackageForAllUsers(deletedAppName);
+ removeDataDirsLI(deletedAppName);
} else {
msg = "Updated system app + " + deletedAppName
+ " no longer present; removing system privileges for "
@@ -1297,13 +1404,7 @@ public class PackageManagerService extends IPackageManager.Stub {
void cleanupInstallFailedPackage(PackageSetting ps) {
Slog.i(TAG, "Cleaning up incompletely installed app: " + ps.name);
- int retCode = mInstaller.remove(ps.name, 0);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove app data directory for package: "
- + ps.name + ", retcode=" + retCode);
- } else {
- sUserManager.removePackageForAllUsers(ps.name);
- }
+ removeDataDirsLI(ps.name);
if (ps.codePath != null) {
if (!ps.codePath.delete()) {
Slog.w(TAG, "Unable to remove old code file: " + ps.codePath);
@@ -1533,19 +1634,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;
@@ -1556,6 +1655,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get package info");
// reader
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
@@ -1598,18 +1698,19 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public int getPackageUid(String packageName, int userId) {
if (!sUserManager.exists(userId)) return -1;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get package uid");
// reader
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
if(p != null) {
- return UserId.getUid(userId, p.applicationInfo.uid);
+ return UserHandle.getUid(userId, p.applicationInfo.uid);
}
PackageSetting ps = mSettings.mPackages.get(packageName);
if((ps == null) || (ps.pkg == null) || (ps.pkg.applicationInfo == null)) {
return -1;
}
p = ps.pkg;
- return p != null ? UserId.getUid(userId, p.applicationInfo.uid) : -1;
+ return p != null ? UserHandle.getUid(userId, p.applicationInfo.uid) : -1;
}
}
@@ -1712,14 +1813,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;
}
@@ -1729,20 +1831,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 =
- getDataPathForPackage(ps.pkg.packageName, 0).getPath();
- ps.pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
- }
- // ps.pkg.mSetEnabled = ps.getEnabled(userId);
- // ps.pkg.mSetStopped = ps.getStopped(userId);
- return generatePackageInfo(ps.pkg, flags, userId);
+ 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 | ApplicationInfo.FLAG_IS_DATA_ONLY;
+ pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
+ pkg.applicationInfo.sourceDir = ps.codePathString;
+ pkg.applicationInfo.dataDir =
+ getDataPathForPackage(packageName, 0).getPath();
+ pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
+ }
+ // pkg.mSetEnabled = ps.getEnabled(userId);
+ // pkg.mSetStopped = ps.getStopped(userId);
+ return generatePackageInfo(pkg, flags, userId);
}
return null;
}
@@ -1750,6 +1855,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get application info");
// writer
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
@@ -1760,13 +1866,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);
}
}
@@ -1782,9 +1887,11 @@ public class PackageManagerService extends IPackageManager.Stub {
public void run() {
mHandler.removeCallbacks(this);
int retCode = -1;
- retCode = mInstaller.freeCache(freeStorageSize);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't clear application caches");
+ synchronized (mInstallLock) {
+ retCode = mInstaller.freeCache(freeStorageSize);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't clear application caches");
+ }
}
if (observer != null) {
try {
@@ -1805,9 +1912,11 @@ public class PackageManagerService extends IPackageManager.Stub {
public void run() {
mHandler.removeCallbacks(this);
int retCode = -1;
- retCode = mInstaller.freeCache(freeStorageSize);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't clear application caches");
+ synchronized (mInstallLock) {
+ retCode = mInstaller.freeCache(freeStorageSize);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't clear application caches");
+ }
}
if(pi != null) {
try {
@@ -1826,6 +1935,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get activity info");
synchronized (mPackages) {
PackageParser.Activity a = mActivities.mActivities.get(component);
@@ -1833,8 +1943,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;
@@ -1846,6 +1956,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get receiver info");
synchronized (mPackages) {
PackageParser.Activity a = mReceivers.mActivities.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(
@@ -1853,8 +1964,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;
@@ -1863,6 +1974,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get service info");
synchronized (mPackages) {
PackageParser.Service s = mServices.mServices.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(
@@ -1870,8 +1982,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;
@@ -1880,6 +1992,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get provider info");
synchronized (mPackages) {
PackageParser.Provider p = mProvidersByComponent.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(
@@ -1887,8 +2000,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;
@@ -1933,7 +2046,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private void checkValidCaller(int uid, int userId) {
- if (UserId.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0)
+ if (UserHandle.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0)
return;
throw new SecurityException("Caller uid=" + uid
@@ -1962,7 +2075,7 @@ public class PackageManagerService extends IPackageManager.Stub {
public int checkUidPermission(String permName, int uid) {
synchronized (mPackages) {
- Object obj = mSettings.getUserIdLPr(UserId.getAppId(uid));
+ Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
if (obj != null) {
GrantedPermissions gp = (GrantedPermissions)obj;
if (gp.grantedPermissions.contains(permName)) {
@@ -1981,6 +2094,34 @@ public class PackageManagerService extends IPackageManager.Stub {
return PackageManager.PERMISSION_DENIED;
}
+ /**
+ * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS
+ * or INTERACT_ACROSS_USERS_FULL permissions, if the userid is not for the caller.
+ * @param message the message to log on security exception
+ * @return
+ */
+ private void enforceCrossUserPermission(int callingUid, int userId,
+ boolean requireFullPermission, String message) {
+ if (userId < 0) {
+ throw new IllegalArgumentException("Invalid userId " + userId);
+ }
+ if (userId == UserHandle.getUserId(callingUid)) return;
+ if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
+ if (requireFullPermission) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
+ } else {
+ try {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
+ } catch (SecurityException se) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS, message);
+ }
+ }
+ }
+ }
+
private BasePermission findPermissionTreeLP(String permName) {
for(BasePermission bp : mSettings.mPermissionTrees.values()) {
if (permName.startsWith(bp.name) &&
@@ -1996,7 +2137,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (permName != null) {
BasePermission bp = findPermissionTreeLP(permName);
if (bp != null) {
- if (bp.uid == UserId.getAppId(Binder.getCallingUid())) {
+ if (bp.uid == UserHandle.getAppId(Binder.getCallingUid())) {
return bp;
}
throw new SecurityException("Calling uid "
@@ -2199,8 +2340,8 @@ public class PackageManagerService extends IPackageManager.Stub {
public int checkUidSignatures(int uid1, int uid2) {
// Map to base uids.
- uid1 = UserId.getAppId(uid1);
- uid2 = UserId.getAppId(uid2);
+ uid1 = UserHandle.getAppId(uid1);
+ uid2 = UserHandle.getAppId(uid2);
// reader
synchronized (mPackages) {
Signature[] s1;
@@ -2258,7 +2399,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
public String[] getPackagesForUid(int uid) {
- uid = UserId.getAppId(uid);
+ uid = UserHandle.getAppId(uid);
// reader
synchronized (mPackages) {
Object obj = mSettings.getUserIdLPr(uid);
@@ -2283,7 +2424,7 @@ public class PackageManagerService extends IPackageManager.Stub {
public String getNameForUid(int uid) {
// reader
synchronized (mPackages) {
- Object obj = mSettings.getUserIdLPr(UserId.getAppId(uid));
+ Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
return sus.name + ":" + sus.userId;
@@ -2313,6 +2454,7 @@ public class PackageManagerService extends IPackageManager.Stub {
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "resolve intent");
List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
return chooseBestActivity(intent, resolvedType, flags, query, userId);
}
@@ -2394,6 +2536,9 @@ public class PackageManagerService extends IPackageManager.Stub {
final int M = prefs.size();
for (int i=0; i<M; i++) {
final PreferredActivity pa = prefs.get(i);
+ if (pa.mUserId != userId) {
+ continue;
+ }
if (pa.mPref.mMatch != match) {
continue;
}
@@ -2451,6 +2596,7 @@ public class PackageManagerService extends IPackageManager.Stub {
public List<ResolveInfo> queryIntentActivities(Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "query intent activities");
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -2490,6 +2636,8 @@ public class PackageManagerService extends IPackageManager.Stub {
Intent[] specifics, String[] specificTypes, Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false,
+ "query intent activity options");
final String resultsAction = intent.getAction();
List<ResolveInfo> results = queryIntentActivities(intent, resolvedType, flags
@@ -2759,11 +2907,14 @@ public class PackageManagerService extends IPackageManager.Stub {
return index;
}
- public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, String lastRead) {
+ @Override
+ public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, String lastRead,
+ int userId) {
final ParceledListSlice<PackageInfo> list = new ParceledListSlice<PackageInfo>();
final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
final String[] keys;
- int userId = UserId.getCallingUserId();
+
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "get installed packages");
// writer
synchronized (mPackages) {
@@ -2838,8 +2989,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);
}
}
@@ -2862,17 +3013,20 @@ public class PackageManagerService extends IPackageManager.Stub {
// reader
synchronized (mPackages) {
final Iterator<PackageParser.Package> i = mPackages.values().iterator();
- final int userId = UserId.getCallingUserId();
+ final int userId = UserHandle.getCallingUserId();
while (i.hasNext()) {
final PackageParser.Package p = i.next();
if (p.applicationInfo != null
&& (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);
+ }
+ }
}
}
}
@@ -2889,14 +3043,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;
}
}
@@ -2910,20 +3062,21 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
final Iterator<Map.Entry<String, PackageParser.Provider>> i = mProviders.entrySet()
.iterator();
- final int userId = UserId.getCallingUserId();
+ final int userId = UserHandle.getCallingUserId();
while (i.hasNext()) {
Map.Entry<String, PackageParser.Provider> entry = i.next();
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);
+ }
}
}
}
@@ -2937,24 +3090,25 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
final Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator();
final int userId = processName != null ?
- UserId.getUserId(uid) : UserId.getCallingUserId();
+ UserHandle.getUserId(uid) : UserHandle.getCallingUserId();
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)
- && UserId.isSameApp(p.info.applicationInfo.uid, uid)))
+ && UserHandle.isSameApp(p.info.applicationInfo.uid, uid)))
&& mSettings.isEnabledLPr(p.info, flags, userId)
&& (!mSafeMode
|| (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
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);
+ if (info != null) {
+ finalList.add(info);
+ }
}
}
}
@@ -2987,8 +3141,11 @@ public class PackageManagerService extends IPackageManager.Stub {
final PackageParser.Instrumentation p = i.next();
if (targetPackage == null
|| targetPackage.equals(p.info.targetPackage)) {
- finalList.add(PackageParser.generateInstrumentationInfo(p,
- flags));
+ InstrumentationInfo ii = PackageParser.generateInstrumentationInfo(p,
+ flags);
+ if (ii != null) {
+ finalList.add(ii);
+ }
}
}
}
@@ -3015,7 +3172,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) {
@@ -3083,7 +3240,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;
@@ -3149,7 +3306,7 @@ public class PackageManagerService extends IPackageManager.Stub {
InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString);
- synchronized (mInstaller) {
+ synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
synchronized (mPackages) {
@@ -3183,7 +3340,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 {
/*
@@ -3205,7 +3362,7 @@ public class PackageManagerService extends IPackageManager.Stub {
+ " better than installed " + ps.versionCode);
InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString);
- synchronized (mInstaller) {
+ synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
}
@@ -3236,7 +3393,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
@@ -3378,8 +3535,8 @@ public class PackageManagerService extends IPackageManager.Stub {
return DEX_OPT_DEFERRED;
} else {
Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName);
- ret = mInstaller.dexopt(path, pkg.applicationInfo.uid,
- !isForwardLocked(pkg));
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg));
pkg.mDidDexOpt = true;
performed = true;
}
@@ -3439,8 +3596,45 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ private int createDataDirsLI(String packageName, int uid) {
+ int[] users = sUserManager.getUserIds();
+ int res = mInstaller.install(packageName, uid, uid);
+ if (res < 0) {
+ return res;
+ }
+ for (int user : users) {
+ if (user != 0) {
+ res = mInstaller.createUserData(packageName,
+ UserHandle.getUid(user, uid), user);
+ if (res < 0) {
+ return res;
+ }
+ }
+ }
+ return res;
+ }
+
+ private int removeDataDirsLI(String packageName) {
+ int[] users = sUserManager.getUserIds();
+ int res = 0;
+ for (int user : users) {
+ int resInner = mInstaller.remove(packageName, user);
+ if (resInner < 0) {
+ res = resInner;
+ }
+ }
+
+ final File nativeLibraryFile = new File(mAppLibInstallDir, packageName);
+ NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryFile);
+ if (!nativeLibraryFile.delete()) {
+ Slog.w(TAG, "Couldn't delete native library directory " + nativeLibraryFile.getPath());
+ }
+
+ return res;
+ }
+
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) {
@@ -3632,7 +3826,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;
@@ -3791,11 +3985,9 @@ public class PackageManagerService extends IPackageManager.Stub {
|| (scanMode&SCAN_BOOTING) != 0)) {
// If this is a system app, we can at least delete its
// current data so the application will still work.
- int ret = mInstaller.remove(pkgName, 0);
+ int ret = removeDataDirsLI(pkgName);
if (ret >= 0) {
// TODO: Kill the processes first
- // Remove the data directories for all users
- sUserManager.removePackageForAllUsers(pkgName);
// Old data gone!
String prefix = (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
? "System package " : "Third party package ";
@@ -3807,8 +3999,7 @@ public class PackageManagerService extends IPackageManager.Stub {
recovered = true;
// And now re-install the app.
- ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
- pkg.applicationInfo.uid);
+ ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
if (ret == -1) {
// Ack should not happen!
msg = prefix + pkg.packageName
@@ -3817,9 +4008,6 @@ public class PackageManagerService extends IPackageManager.Stub {
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
}
- // Create data directories for all users
- sUserManager.installPackageForAllUsers(pkgName,
- pkg.applicationInfo.uid);
}
if (!recovered) {
mHasSystemUidErrors = true;
@@ -3857,15 +4045,12 @@ public class PackageManagerService extends IPackageManager.Stub {
Log.v(TAG, "Want this data dir: " + dataPath);
}
//invoke installer to do the actual installation
- int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
- pkg.applicationInfo.uid);
+ int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
if (ret < 0) {
// Error from installer
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
}
- // Create data directories for all users
- sUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
if (dataPath.exists()) {
pkg.applicationInfo.dataDir = dataPath.getPath();
@@ -3886,9 +4071,7 @@ public class PackageManagerService extends IPackageManager.Stub {
*/
if (pkg.applicationInfo.nativeLibraryDir == null && pkg.applicationInfo.dataDir != null) {
if (pkgSetting.nativeLibraryPathString == null) {
- final String nativeLibraryPath = new File(dataPath, LIB_DIR_NAME).getPath();
- pkg.applicationInfo.nativeLibraryDir = nativeLibraryPath;
- pkgSetting.nativeLibraryPathString = nativeLibraryPath;
+ setInternalAppNativeLibraryPath(pkg, pkgSetting);
} else {
pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString;
}
@@ -3910,7 +4093,7 @@ public class PackageManagerService extends IPackageManager.Stub {
*/
if (pkg.applicationInfo.nativeLibraryDir != null) {
try {
- final File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
+ File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
final String dataPathString = dataPath.getCanonicalPath();
if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
@@ -3925,37 +4108,43 @@ public class PackageManagerService extends IPackageManager.Stub {
Log.i(TAG, "removed obsolete native libraries for system package "
+ path);
}
- } else if (nativeLibraryDir.getParentFile().getCanonicalPath()
- .equals(dataPathString)) {
- /*
- * Make sure the native library dir isn't a symlink to
- * something. If it is, ask installd to remove it and create
- * a directory so we can copy to it afterwards.
- */
- boolean isSymLink;
- try {
- isSymLink = S_ISLNK(Libcore.os.lstat(nativeLibraryDir.getPath()).st_mode);
- } catch (ErrnoException e) {
- // This shouldn't happen, but we'll fail-safe.
- isSymLink = true;
+ } else if (!isForwardLocked(pkg) && !isExternal(pkg)) {
+ // Update native library dir if it starts with /data/data
+ if (nativeLibraryDir.getPath().startsWith(dataPathString)) {
+ setInternalAppNativeLibraryPath(pkg, pkgSetting);
+ nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
}
- if (isSymLink) {
- mInstaller.unlinkNativeLibraryDirectory(dataPathString);
+
+ try {
+ if (copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir) != PackageManager.INSTALL_SUCCEEDED) {
+ Slog.e(TAG, "Unable to copy native libraries");
+ mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ return null;
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to copy native libraries", e);
+ mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ return null;
}
- /*
- * If this is an internal application or our
- * nativeLibraryPath points to our data directory, unpack
- * the libraries if necessary.
- */
- NativeLibraryHelper.copyNativeBinariesIfNeededLI(scanFile, nativeLibraryDir);
+ if (mInstaller.linkNativeLibraryDirectory(dataPathString,
+ pkg.applicationInfo.nativeLibraryDir) == -1) {
+ Slog.e(TAG, "Unable to link native library directory");
+ mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ return null;
+ }
} else {
Slog.i(TAG, "Linking native library dir for " + path);
- mInstaller.linkNativeLibraryDirectory(dataPathString,
+ int ret = mInstaller.linkNativeLibraryDirectory(dataPathString,
pkg.applicationInfo.nativeLibraryDir);
+ if (ret < 0) {
+ Slog.w(TAG, "Failed linking native library dir for " + path);
+ mLastScanError = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+ return null;
+ }
}
} catch (IOException ioe) {
- Log.e(TAG, "Unable to get canonical file " + ioe.toString());
+ Slog.e(TAG, "Unable to get canonical file " + ioe.toString());
}
}
pkg.mScanPath = path;
@@ -3992,7 +4181,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) {
@@ -4268,20 +4459,75 @@ public class PackageManagerService extends IPackageManager.Stub {
return pkg;
}
- private void killApplication(String pkgName, int uid) {
+ private void setInternalAppNativeLibraryPath(PackageParser.Package pkg,
+ PackageSetting pkgSetting) {
+ final String apkLibPath = getApkName(pkgSetting.codePathString);
+ final String nativeLibraryPath = new File(mAppLibInstallDir, apkLibPath).getPath();
+ pkg.applicationInfo.nativeLibraryDir = nativeLibraryPath;
+ pkgSetting.nativeLibraryPathString = nativeLibraryPath;
+ }
+
+ private static int copyNativeLibrariesForInternalApp(File scanFile, final File nativeLibraryDir)
+ throws IOException {
+ if (!nativeLibraryDir.isDirectory()) {
+ nativeLibraryDir.delete();
+
+ if (!nativeLibraryDir.mkdir()) {
+ throw new IOException("Cannot create " + nativeLibraryDir.getPath());
+ }
+
+ try {
+ Libcore.os.chmod(nativeLibraryDir.getPath(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH
+ | S_IXOTH);
+ } catch (ErrnoException e) {
+ throw new IOException("Cannot chmod native library directory "
+ + nativeLibraryDir.getPath(), e);
+ }
+ } else if (!SELinux.restorecon(nativeLibraryDir)) {
+ throw new IOException("Cannot set SELinux context for " + nativeLibraryDir.getPath());
+ }
+
+ /*
+ * If this is an internal application or our nativeLibraryPath points to
+ * the app-lib directory, unpack the libraries if necessary.
+ */
+ return NativeLibraryHelper.copyNativeBinariesIfNeededLI(scanFile, nativeLibraryDir);
+ }
+
+ private void killApplication(String pkgName, int appId) {
// Request the ActivityManager to kill the process(only for existing packages)
// so that we do not end up in a confused state while the user is still using the older
// version of the application while the new one gets installed.
IActivityManager am = ActivityManagerNative.getDefault();
if (am != null) {
try {
- am.killApplicationWithUid(pkgName, uid);
+ am.killApplicationWithAppId(pkgName, appId);
} catch (RemoteException e) {
}
}
}
- void removePackageLI(PackageParser.Package pkg, boolean chatty) {
+ void removePackageLI(PackageSetting ps, boolean chatty) {
+ if (DEBUG_INSTALL) {
+ if (chatty)
+ Log.d(TAG, "Removing package " + ps.name);
+ }
+
+ // writer
+ synchronized (mPackages) {
+ mPackages.remove(ps.name);
+ if (ps.codePathString != null) {
+ mAppDirs.remove(ps.codePathString);
+ }
+
+ final PackageParser.Package pkg = ps.pkg;
+ if (pkg != null) {
+ cleanPackageDataStructuresLILPw(pkg, chatty);
+ }
+ }
+ }
+
+ void removeInstalledPackageLI(PackageParser.Package pkg, boolean chatty) {
if (DEBUG_INSTALL) {
if (chatty)
Log.d(TAG, "Removing package " + pkg.applicationInfo.packageName);
@@ -4293,143 +4539,146 @@ public class PackageManagerService extends IPackageManager.Stub {
if (pkg.mPath != null) {
mAppDirs.remove(pkg.mPath);
}
+ cleanPackageDataStructuresLILPw(pkg, chatty);
+ }
+ }
- int N = pkg.providers.size();
- StringBuilder r = null;
- int i;
- for (i=0; i<N; i++) {
- PackageParser.Provider p = pkg.providers.get(i);
- mProvidersByComponent.remove(new ComponentName(p.info.packageName,
- p.info.name));
- if (p.info.authority == null) {
-
- /* The is another ContentProvider with this authority when
- * this app was installed so this authority is null,
- * Ignore it as we don't have to unregister the provider.
- */
- continue;
- }
- String names[] = p.info.authority.split(";");
- for (int j = 0; j < names.length; j++) {
- if (mProviders.get(names[j]) == p) {
- mProviders.remove(names[j]);
- if (DEBUG_REMOVE) {
- if (chatty)
- Log.d(TAG, "Unregistered content provider: " + names[j]
- + ", className = " + p.info.name + ", isSyncable = "
- + p.info.isSyncable);
- }
- }
- }
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(p.info.name);
- }
- }
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Providers: " + r);
+ void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) {
+ int N = pkg.providers.size();
+ StringBuilder r = null;
+ int i;
+ for (i=0; i<N; i++) {
+ PackageParser.Provider p = pkg.providers.get(i);
+ mProvidersByComponent.remove(new ComponentName(p.info.packageName,
+ p.info.name));
+ if (p.info.authority == null) {
+
+ /* There was another ContentProvider with this authority when
+ * this app was installed so this authority is null,
+ * Ignore it as we don't have to unregister the provider.
+ */
+ continue;
}
-
- N = pkg.services.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Service s = pkg.services.get(i);
- mServices.removeService(s);
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
+ String names[] = p.info.authority.split(";");
+ for (int j = 0; j < names.length; j++) {
+ if (mProviders.get(names[j]) == p) {
+ mProviders.remove(names[j]);
+ if (DEBUG_REMOVE) {
+ if (chatty)
+ Log.d(TAG, "Unregistered content provider: " + names[j]
+ + ", className = " + p.info.name + ", isSyncable = "
+ + p.info.isSyncable);
}
- r.append(s.info.name);
}
}
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Services: " + r);
+ if (chatty) {
+ if (r == null) {
+ r = new StringBuilder(256);
+ } else {
+ r.append(' ');
+ }
+ r.append(p.info.name);
}
+ }
+ if (r != null) {
+ if (DEBUG_REMOVE) Log.d(TAG, " Providers: " + r);
+ }
- N = pkg.receivers.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Activity a = pkg.receivers.get(i);
- mReceivers.removeActivity(a, "receiver");
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(a.info.name);
+ N = pkg.services.size();
+ r = null;
+ for (i=0; i<N; i++) {
+ PackageParser.Service s = pkg.services.get(i);
+ mServices.removeService(s);
+ if (chatty) {
+ if (r == null) {
+ r = new StringBuilder(256);
+ } else {
+ r.append(' ');
}
+ r.append(s.info.name);
}
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Receivers: " + r);
- }
+ }
+ if (r != null) {
+ if (DEBUG_REMOVE) Log.d(TAG, " Services: " + r);
+ }
- N = pkg.activities.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Activity a = pkg.activities.get(i);
- mActivities.removeActivity(a, "activity");
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(a.info.name);
+ N = pkg.receivers.size();
+ r = null;
+ for (i=0; i<N; i++) {
+ PackageParser.Activity a = pkg.receivers.get(i);
+ mReceivers.removeActivity(a, "receiver");
+ if (chatty) {
+ if (r == null) {
+ r = new StringBuilder(256);
+ } else {
+ r.append(' ');
}
+ r.append(a.info.name);
}
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Activities: " + r);
- }
+ }
+ if (r != null) {
+ if (DEBUG_REMOVE) Log.d(TAG, " Receivers: " + r);
+ }
- N = pkg.permissions.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Permission p = pkg.permissions.get(i);
- BasePermission bp = mSettings.mPermissions.get(p.info.name);
- if (bp == null) {
- bp = mSettings.mPermissionTrees.get(p.info.name);
- }
- if (bp != null && bp.perm == p) {
- bp.perm = null;
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(p.info.name);
- }
+ N = pkg.activities.size();
+ r = null;
+ for (i=0; i<N; i++) {
+ PackageParser.Activity a = pkg.activities.get(i);
+ mActivities.removeActivity(a, "activity");
+ if (chatty) {
+ if (r == null) {
+ r = new StringBuilder(256);
+ } else {
+ r.append(' ');
}
+ r.append(a.info.name);
}
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r);
- }
+ }
+ if (r != null) {
+ if (DEBUG_REMOVE) Log.d(TAG, " Activities: " + r);
+ }
- N = pkg.instrumentation.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Instrumentation a = pkg.instrumentation.get(i);
- mInstrumentation.remove(a.getComponentName());
+ N = pkg.permissions.size();
+ r = null;
+ for (i=0; i<N; i++) {
+ PackageParser.Permission p = pkg.permissions.get(i);
+ BasePermission bp = mSettings.mPermissions.get(p.info.name);
+ if (bp == null) {
+ bp = mSettings.mPermissionTrees.get(p.info.name);
+ }
+ if (bp != null && bp.perm == p) {
+ bp.perm = null;
if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
- r.append(a.info.name);
+ r.append(p.info.name);
}
}
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Instrumentation: " + r);
+ }
+ if (r != null) {
+ if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r);
+ }
+
+ N = pkg.instrumentation.size();
+ r = null;
+ for (i=0; i<N; i++) {
+ PackageParser.Instrumentation a = pkg.instrumentation.get(i);
+ mInstrumentation.remove(a.getComponentName());
+ if (chatty) {
+ if (r == null) {
+ r = new StringBuilder(256);
+ } else {
+ r.append(' ');
+ }
+ r.append(a.info.name);
}
}
+ if (r != null) {
+ if (DEBUG_REMOVE) Log.d(TAG, " Instrumentation: " + r);
+ }
}
private static final boolean isPackageFilename(String name) {
@@ -4716,14 +4965,17 @@ public class PackageManagerService extends IPackageManager.Stub {
mFlags = flags;
final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
final int N = packageActivities.size();
- ArrayList<ArrayList<PackageParser.ActivityIntentInfo>> listCut =
- new ArrayList<ArrayList<PackageParser.ActivityIntentInfo>>(N);
+ ArrayList<PackageParser.ActivityIntentInfo[]> listCut =
+ new ArrayList<PackageParser.ActivityIntentInfo[]>(N);
ArrayList<PackageParser.ActivityIntentInfo> intentFilters;
for (int i = 0; i < N; ++i) {
intentFilters = packageActivities.get(i).intents;
if (intentFilters != null && intentFilters.size() > 0) {
- listCut.add(intentFilters);
+ PackageParser.ActivityIntentInfo[] array =
+ new PackageParser.ActivityIntentInfo[intentFilters.size()];
+ intentFilters.toArray(array);
+ listCut.add(array);
}
}
return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
@@ -4791,6 +5043,11 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
+ protected ActivityIntentInfo[] newArray(int size) {
+ return new ActivityIntentInfo[size];
+ }
+
+ @Override
protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) {
if (!sUserManager.exists(userId)) return true;
PackageParser.Package p = filter.activity.owner;
@@ -4800,7 +5057,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;
@@ -4823,12 +5081,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;
}
@@ -4904,14 +5167,17 @@ public class PackageManagerService extends IPackageManager.Stub {
mFlags = flags;
final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
final int N = packageServices.size();
- ArrayList<ArrayList<PackageParser.ServiceIntentInfo>> listCut =
- new ArrayList<ArrayList<PackageParser.ServiceIntentInfo>>(N);
+ ArrayList<PackageParser.ServiceIntentInfo[]> listCut =
+ new ArrayList<PackageParser.ServiceIntentInfo[]>(N);
ArrayList<PackageParser.ServiceIntentInfo> intentFilters;
for (int i = 0; i < N; ++i) {
intentFilters = packageServices.get(i).intents;
if (intentFilters != null && intentFilters.size() > 0) {
- listCut.add(intentFilters);
+ PackageParser.ServiceIntentInfo[] array =
+ new PackageParser.ServiceIntentInfo[intentFilters.size()];
+ intentFilters.toArray(array);
+ listCut.add(array);
}
}
return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
@@ -4974,6 +5240,11 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
+ protected PackageParser.ServiceIntentInfo[] newArray(int size) {
+ return new PackageParser.ServiceIntentInfo[size];
+ }
+
+ @Override
protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter, int userId) {
if (!sUserManager.exists(userId)) return true;
PackageParser.Package p = filter.service.owner;
@@ -4983,8 +5254,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;
@@ -5008,12 +5279,17 @@ 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);
+ if (si == null) {
+ return null;
+ }
+ final ResolveInfo res = new ResolveInfo();
+ res.serviceInfo = si;
if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
res.filter = filter;
}
@@ -5104,13 +5380,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 == UserId.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);
@@ -5122,11 +5399,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) {
- uid = UserId.getUid(id, UserId.getAppId(uid));
+ 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);
}
@@ -5144,8 +5428,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,
@@ -5153,34 +5438,66 @@ 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;
+ mSettings.mPackagesToBeCleaned.remove(userId);
+ }
+ // 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) {
}
}
@@ -5195,9 +5512,11 @@ public class PackageManagerService extends IPackageManager.Stub {
public void onEvent(int event, String path) {
String removedPackage = null;
- int removedUid = -1;
+ int removedAppId = -1;
+ int[] removedUsers = null;
String addedPackage = null;
- int addedUid = -1;
+ int addedAppId = -1;
+ int[] addedUsers = null;
// TODO post a message to the handler to obtain serial ordering
synchronized (mInstallLock) {
@@ -5223,15 +5542,25 @@ public class PackageManagerService extends IPackageManager.Stub {
return;
}
PackageParser.Package p = null;
+ PackageSetting ps = null;
// reader
synchronized (mPackages) {
p = mAppDirs.get(fullPathStr);
+ if (p != null) {
+ ps = mSettings.mPackages.get(p.applicationInfo.packageName);
+ if (ps != null) {
+ removedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+ } else {
+ removedUsers = sUserManager.getUserIds();
+ }
+ }
+ addedUsers = sUserManager.getUserIds();
}
if ((event&REMOVE_EVENTS) != 0) {
- if (p != null) {
- removePackageLI(p, true);
- removedPackage = p.applicationInfo.packageName;
- removedUid = p.applicationInfo.uid;
+ if (ps != null) {
+ removePackageLI(ps, true);
+ removedPackage = ps.name;
+ removedAppId = ps.appId;
}
}
@@ -5243,7 +5572,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(), UserHandle.ALL);
if (p != null) {
/*
* TODO this seems dangerous as the package may have
@@ -5256,7 +5585,7 @@ public class PackageManagerService extends IPackageManager.Stub {
p.permissions.size() > 0 ? UPDATE_PERMISSIONS_ALL : 0);
}
addedPackage = p.applicationInfo.packageName;
- addedUid = p.applicationInfo.uid;
+ addedAppId = UserHandle.getAppId(p.applicationInfo.uid);
}
}
}
@@ -5269,16 +5598,16 @@ public class PackageManagerService extends IPackageManager.Stub {
if (removedPackage != null) {
Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, removedUid);
+ extras.putInt(Intent.EXTRA_UID, removedAppId);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
- extras, null, null, UserId.USER_ALL);
+ extras, null, null, removedUsers);
}
if (addedPackage != null) {
Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, addedUid);
+ extras.putInt(Intent.EXTRA_UID, addedAppId);
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,
- extras, null, null, UserId.USER_ALL);
+ extras, null, null, addedUsers);
}
}
@@ -5304,9 +5633,25 @@ public class PackageManagerService extends IPackageManager.Stub {
public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
int flags, String installerPackageName, Uri verificationURI,
ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
+ VerificationParams verificationParams = new VerificationParams(verificationURI, null, null,
+ manifestDigest);
+ installPackageWithVerificationAndEncryption(packageURI, observer, flags,
+ installerPackageName, verificationParams, encryptionParams);
+ }
+
+ public void installPackageWithVerificationAndEncryption(Uri packageURI,
+ IPackageInstallObserver observer, int flags, String installerPackageName,
+ VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
+ null);
final int uid = Binder.getCallingUid();
+ UserHandle user;
+ if ((flags&PackageManager.INSTALL_ALL_USERS) != 0) {
+ user = UserHandle.ALL;
+ } else {
+ user = new UserHandle(UserHandle.getUserId(uid));
+ }
final int filteredFlags;
@@ -5319,14 +5664,61 @@ public class PackageManagerService extends IPackageManager.Stub {
filteredFlags = flags & ~PackageManager.INSTALL_FROM_ADB;
}
+ verificationParams.setInstallerUid(uid);
+
final Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName,
- verificationURI, manifestDigest, 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 {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
+ "Only package verification agents can verify applications");
+
final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED);
final PackageVerificationResponse response = new PackageVerificationResponse(
verificationCode, Binder.getCallingUid());
@@ -5335,6 +5727,49 @@ public class PackageManagerService extends IPackageManager.Stub {
mHandler.sendMessage(msg);
}
+ @Override
+ public void extendVerificationTimeout(int id, int verificationCodeAtTimeout,
+ long millisecondsToDelay) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
+ "Only package verification agents can extend verification timeouts");
+
+ final PackageVerificationState state = mPendingVerification.get(id);
+ final PackageVerificationResponse response = new PackageVerificationResponse(
+ verificationCodeAtTimeout, Binder.getCallingUid());
+
+ if (millisecondsToDelay > PackageManager.MAXIMUM_VERIFICATION_TIMEOUT) {
+ millisecondsToDelay = PackageManager.MAXIMUM_VERIFICATION_TIMEOUT;
+ }
+ if (millisecondsToDelay < 0) {
+ millisecondsToDelay = 0;
+ }
+ if ((verificationCodeAtTimeout != PackageManager.VERIFICATION_ALLOW)
+ && (verificationCodeAtTimeout != PackageManager.VERIFICATION_REJECT)) {
+ verificationCodeAtTimeout = PackageManager.VERIFICATION_REJECT;
+ }
+
+ if ((state != null) && !state.timeoutExtended()) {
+ state.extendTimeout();
+
+ final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED);
+ msg.arg1 = id;
+ msg.obj = response;
+ mHandler.sendMessageDelayed(msg, millisecondsToDelay);
+ }
+ }
+
+ private void broadcastPackageVerified(int verificationId, Uri packageUri,
+ int verificationCode) {
+ final Intent intent = new Intent(Intent.ACTION_PACKAGE_VERIFIED);
+ intent.setDataAndType(packageUri, PACKAGE_MIME_TYPE);
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
+ intent.putExtra(PackageManager.EXTRA_VERIFICATION_RESULT, verificationCode);
+
+ mContext.sendBroadcast(intent, android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
+ }
+
private ComponentName matchComponentForVerifier(String packageName,
List<ResolveInfo> receivers) {
ActivityInfo targetReceiver = null;
@@ -5447,20 +5882,45 @@ public class PackageManagerService extends IPackageManager.Stub {
* @return verification timeout in milliseconds
*/
private long getVerificationTimeout() {
- return android.provider.Settings.Secure.getLong(mContext.getContentResolver(),
- android.provider.Settings.Secure.PACKAGE_VERIFIER_TIMEOUT,
+ return android.provider.Settings.Global.getLong(mContext.getContentResolver(),
+ android.provider.Settings.Global.PACKAGE_VERIFIER_TIMEOUT,
DEFAULT_VERIFICATION_TIMEOUT);
}
/**
+ * Get the default verification agent response code.
+ *
+ * @return default verification response code
+ */
+ private int getDefaultVerificationResponse() {
+ return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
+ DEFAULT_VERIFICATION_RESPONSE);
+ }
+
+ /**
* Check whether or not package verification has been enabled.
*
* @return true if verification should be performed
*/
private boolean isVerificationEnabled() {
+ if (!DEFAULT_VERIFY_ENABLE) {
+ return false;
+ }
+
+ return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) == 1;
+ }
+
+ /**
+ * Get the "allow unknown sources" setting.
+ *
+ * @return the current "allow unknown sources" setting
+ */
+ private int getUnknownSourcesSettings() {
return android.provider.Settings.Secure.getInt(mContext.getContentResolver(),
- android.provider.Settings.Secure.PACKAGE_VERIFIER_ENABLE,
- DEFAULT_VERIFY_ENABLE ? 1 : 0) == 1 ? true : false;
+ android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS,
+ -1);
}
public void setInstallerPackageName(String targetPackage, String installerPackageName) {
@@ -5615,6 +6075,17 @@ public class PackageManagerService extends IPackageManager.Stub {
*/
private int mRetries = 0;
+ /** User handle for the user requesting the information or installation. */
+ private final UserHandle mUser;
+
+ HandlerParams(UserHandle user) {
+ mUser = user;
+ }
+
+ UserHandle getUser() {
+ return mUser;
+ }
+
final boolean startCopy() {
boolean res;
try {
@@ -5656,6 +6127,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private final IPackageStatsObserver mObserver;
public MeasureParams(PackageStats stats, IPackageStatsObserver observer) {
+ super(new UserHandle(stats.userHandle));
mObserver = observer;
mStats = stats;
}
@@ -5663,7 +6135,7 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
void handleStartCopy() throws RemoteException {
synchronized (mInstallLock) {
- mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats);
+ mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats.userHandle, mStats);
}
final boolean mounted;
@@ -5671,19 +6143,20 @@ public class PackageManagerService extends IPackageManager.Stub {
mounted = true;
} else {
final String status = Environment.getExternalStorageState();
-
- mounted = status.equals(Environment.MEDIA_MOUNTED)
- || status.equals(Environment.MEDIA_MOUNTED_READ_ONLY);
+ mounted = (Environment.MEDIA_MOUNTED.equals(status)
+ || Environment.MEDIA_MOUNTED_READ_ONLY.equals(status));
}
if (mounted) {
- final File externalCacheDir = Environment
+ final UserEnvironment userEnv = new UserEnvironment(mStats.userHandle);
+
+ final File externalCacheDir = userEnv
.getExternalStorageAppCacheDirectory(mStats.packageName);
final long externalCacheSize = mContainerService
.calculateDirectorySize(externalCacheDir.getPath());
mStats.externalCacheSize = externalCacheSize;
- final File externalDataDir = Environment
+ final File externalDataDir = userEnv
.getExternalStorageAppDataDirectory(mStats.packageName);
long externalDataSize = mContainerService.calculateDirectorySize(externalDataDir
.getPath());
@@ -5693,12 +6166,12 @@ public class PackageManagerService extends IPackageManager.Stub {
}
mStats.externalDataSize = externalDataSize;
- final File externalMediaDir = Environment
+ final File externalMediaDir = userEnv
.getExternalStorageAppMediaDirectory(mStats.packageName);
mStats.externalMediaSize = mContainerService
.calculateDirectorySize(externalMediaDir.getPath());
- final File externalObbDir = Environment
+ final File externalObbDir = userEnv
.getExternalStorageAppObbDirectory(mStats.packageName);
mStats.externalObbSize = mContainerService.calculateDirectorySize(externalObbDir
.getPath());
@@ -5729,8 +6202,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private final Uri mPackageURI;
final String installerPackageName;
- final Uri verificationURI;
- final ManifestDigest manifestDigest;
+ final VerificationParams verificationParams;
private InstallArgs mArgs;
private int mRet;
private File mTempPackage;
@@ -5738,17 +6210,24 @@ public class PackageManagerService extends IPackageManager.Stub {
InstallParams(Uri packageURI,
IPackageInstallObserver observer, int flags,
- String installerPackageName, Uri verificationURI, ManifestDigest manifestDigest,
- ContainerEncryptionParams encryptionParams) {
+ String installerPackageName, VerificationParams verificationParams,
+ ContainerEncryptionParams encryptionParams, UserHandle user) {
+ super(user);
this.mPackageURI = packageURI;
this.flags = flags;
this.observer = observer;
this.installerPackageName = installerPackageName;
- this.verificationURI = verificationURI;
- this.manifestDigest = manifestDigest;
+ this.verificationParams = verificationParams;
this.encryptionParams = encryptionParams;
}
+ public ManifestDigest getManifestDigest() {
+ if (verificationParams == null) {
+ return null;
+ }
+ return verificationParams.getManifestDigest();
+ }
+
private int installLocationPolicy(PackageInfoLite pkgLite, int flags) {
String packageName = pkgLite.packageName;
int installLocation = pkgLite.installLocation;
@@ -5758,6 +6237,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) {
@@ -5850,7 +6339,8 @@ public class PackageManagerService extends IPackageManager.Stub {
packageFile = mTempPackage;
FileUtils.setPermissions(packageFile.getAbsolutePath(),
- FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IROTH,
+ FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP
+ | FileUtils.S_IROTH,
-1, -1);
} else {
packageFile = null;
@@ -5884,6 +6374,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);
@@ -5919,8 +6411,9 @@ public class PackageManagerService extends IPackageManager.Stub {
verification.setDataAndType(getPackageUri(), PACKAGE_MIME_TYPE);
verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- final List<ResolveInfo> receivers = queryIntentReceivers(verification, null,
- PackageManager.GET_DISABLED_COMPONENTS, 0 /* TODO: Which userId? */);
+ final List<ResolveInfo> receivers = queryIntentReceivers(verification,
+ PACKAGE_MIME_TYPE, PackageManager.GET_DISABLED_COMPONENTS,
+ 0 /* TODO: Which userId? */);
if (DEBUG_VERIFY) {
Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
@@ -5937,9 +6430,29 @@ public class PackageManagerService extends IPackageManager.Stub {
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS, flags);
- if (verificationURI != null) {
- verification.putExtra(PackageManager.EXTRA_VERIFICATION_URI,
- verificationURI);
+ verification.putExtra(PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME,
+ pkgLite.packageName);
+
+ verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
+ pkgLite.versionCode);
+
+ if (verificationParams != null) {
+ if (verificationParams.getVerificationURI() != null) {
+ verification.putExtra(PackageManager.EXTRA_VERIFICATION_URI,
+ verificationParams.getVerificationURI());
+ }
+ if (verificationParams.getOriginatingURI() != null) {
+ verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
+ verificationParams.getOriginatingURI());
+ }
+ if (verificationParams.getReferrer() != null) {
+ verification.putExtra(Intent.EXTRA_REFERRER,
+ verificationParams.getReferrer());
+ }
+ if (verificationParams.getInstallerUid() >= 0) {
+ verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
+ verificationParams.getInstallerUid());
+ }
}
final PackageVerificationState verificationState = new PackageVerificationState(
@@ -6018,12 +6531,12 @@ public class PackageManagerService extends IPackageManager.Stub {
// will succeed.
if (mArgs != null) {
processPendingInstall(mArgs, mRet);
- }
- if (mTempPackage != null) {
- if (!mTempPackage.delete()) {
- Slog.w(TAG, "Couldn't delete temporary file: "
- + mTempPackage.getAbsolutePath());
+ if (mTempPackage != null) {
+ if (!mTempPackage.delete()) {
+ Slog.w(TAG, "Couldn't delete temporary file: " +
+ mTempPackage.getAbsolutePath());
+ }
}
}
}
@@ -6064,7 +6577,8 @@ public class PackageManagerService extends IPackageManager.Stub {
int mRet;
MoveParams(InstallArgs srcArgs, IPackageMoveObserver observer, int flags,
- String packageName, String dataDir, int uid) {
+ String packageName, String dataDir, int uid, UserHandle user) {
+ super(user);
this.srcArgs = srcArgs;
this.observer = observer;
this.flags = flags;
@@ -6217,14 +6731,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();
@@ -6275,11 +6792,12 @@ public class PackageManagerService extends IPackageManager.Stub {
FileInstallArgs(InstallParams params) {
super(params.getPackageUri(), params.observer, params.flags,
- params.installerPackageName, params.manifestDigest);
+ 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;
@@ -6288,12 +6806,12 @@ 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();
resourceFileName = getResourcePathFromCodePath();
- libraryPath = new File(dataDir, LIB_DIR_NAME).getPath();
+ libraryPath = new File(mAppLibInstallDir, pkgName).getPath();
}
boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
@@ -6330,6 +6848,7 @@ public class PackageManagerService extends IPackageManager.Stub {
installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir;
codeFileName = createTempPackageFile(installDir).getPath();
resourceFileName = getResourcePathFromCodePath();
+ libraryPath = getLibraryPathFromCodePath();
created = true;
}
@@ -6384,6 +6903,23 @@ public class PackageManagerService extends IPackageManager.Stub {
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
}
+
+ final File nativeLibraryFile = new File(getNativeLibraryPath());
+ Slog.i(TAG, "Copying native libraries to " + nativeLibraryFile.getPath());
+ if (nativeLibraryFile.exists()) {
+ NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryFile);
+ nativeLibraryFile.delete();
+ }
+ try {
+ int copyRet = copyNativeLibrariesForInternalApp(codeFile, nativeLibraryFile);
+ if (copyRet != PackageManager.INSTALL_SUCCEEDED) {
+ return copyRet;
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Copying native libraries failed", e);
+ ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ }
+
return ret;
}
@@ -6401,6 +6937,7 @@ public class PackageManagerService extends IPackageManager.Stub {
} else {
final File oldCodeFile = new File(getCodePath());
final File oldResourceFile = new File(getResourcePath());
+ final File oldLibraryFile = new File(getNativeLibraryPath());
// Rename APK file based on packageName
final String apkName = getNextCodePath(oldCodePath, pkgName, ".apk");
@@ -6415,7 +6952,20 @@ public class PackageManagerService extends IPackageManager.Stub {
if (isFwdLocked() && !oldResourceFile.renameTo(newResFile)) {
return false;
}
- resourceFileName = getResourcePathFromCodePath();
+ resourceFileName = newResFile.getPath();
+
+ // Rename library path
+ final File newLibraryFile = new File(getLibraryPathFromCodePath());
+ if (newLibraryFile.exists()) {
+ NativeLibraryHelper.removeNativeBinariesFromDirLI(newLibraryFile);
+ newLibraryFile.delete();
+ }
+ if (!oldLibraryFile.renameTo(newLibraryFile)) {
+ Slog.e(TAG, "Cannot rename native library directory "
+ + oldLibraryFile.getPath() + " to " + newLibraryFile.getPath());
+ return false;
+ }
+ libraryPath = newLibraryFile.getPath();
// Attempt to set permissions
if (!setPermissions()) {
@@ -6466,8 +7016,15 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ private String getLibraryPathFromCodePath() {
+ return new File(mAppLibInstallDir, getApkName(getCodePath())).getPath();
+ }
+
@Override
String getNativeLibraryPath() {
+ if (libraryPath == null) {
+ libraryPath = getLibraryPathFromCodePath();
+ }
return libraryPath;
}
@@ -6493,6 +7050,15 @@ public class PackageManagerService extends IPackageManager.Stub {
publicSourceFile.delete();
}
}
+
+ if (libraryPath != null) {
+ File nativeLibraryFile = new File(libraryPath);
+ NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryFile);
+ if (!nativeLibraryFile.delete()) {
+ Slog.w(TAG, "Couldn't delete native library directory " + libraryPath);
+ }
+ }
+
return ret;
}
@@ -6562,13 +7128,15 @@ public class PackageManagerService extends IPackageManager.Stub {
AsecInstallArgs(InstallParams params) {
super(params.getPackageUri(), params.observer, params.flags,
- params.installerPackageName, params.manifestDigest);
+ 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);
@@ -6579,14 +7147,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;
}
@@ -6735,7 +7305,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final int groupOwner;
final String protectedFile;
if (isFwdLocked()) {
- groupOwner = uid;
+ groupOwner = UserHandle.getSharedAppGid(uid);
protectedFile = RES_FILE_NAME;
} else {
groupOwner = -1;
@@ -6817,7 +7387,8 @@ public class PackageManagerService extends IPackageManager.Stub {
int doPostCopy(int uid) {
if (isFwdLocked()) {
if (uid < Process.FIRST_APPLICATION_UID
- || !PackageHelper.fixSdPermissions(cid, uid, RES_FILE_NAME)) {
+ || !PackageHelper.fixSdPermissions(cid, UserHandle.getSharedAppGid(uid),
+ RES_FILE_NAME)) {
Slog.e(TAG, "Failed to finalize " + cid);
PackageHelper.destroySdDir(cid);
return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
@@ -6910,6 +7481,10 @@ public class PackageManagerService extends IPackageManager.Stub {
class PackageInstalledInfo {
String name;
int uid;
+ // The set of users that originally had this package installed.
+ int[] origUsers;
+ // The set of users that now have this package installed.
+ int[] newUsers;
PackageParser.Package pkg;
int returnCode;
PackageRemovedInfo removedInfo;
@@ -6919,14 +7494,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
@@ -6949,7 +7522,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) {
@@ -6966,17 +7539,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;
@@ -6993,15 +7564,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;
@@ -7016,7 +7588,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;
@@ -7025,7 +7597,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) {
@@ -7046,8 +7618,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
@@ -7062,7 +7634,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, null) == null) {
Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade");
return;
}
@@ -7080,8 +7652,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;
@@ -7111,7 +7682,7 @@ public class PackageManagerService extends IPackageManager.Stub {
res.removedInfo.uid = oldPkg.applicationInfo.uid;
res.removedInfo.removedPackage = packageName;
// Remove existing system package
- removePackageLI(oldPkg, true);
+ removePackageLI(oldPkgSetting, true);
// writer
synchronized (mPackages) {
if (!mSettings.disableSystemPackageLPw(packageName) && deletedPackage != null) {
@@ -7130,7 +7701,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) {
@@ -7150,10 +7721,10 @@ public class PackageManagerService extends IPackageManager.Stub {
// Re installation failed. Restore old information
// Remove new pkg information
if (newPackage != null) {
- removePackageLI(newPackage, true);
+ removeInstalledPackageLI(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) {
@@ -7309,6 +7880,7 @@ public class PackageManagerService extends IPackageManager.Stub {
systemApp = (ps.pkg.applicationInfo.flags &
ApplicationInfo.FLAG_SYSTEM) != 0;
}
+ res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
}
@@ -7327,11 +7899,17 @@ 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,
- installerPackageName,res);
+ installNewPackageLI(pkg, parseFlags, scanMode, args.user,
+ installerPackageName, res);
+ }
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(pkgName);
+ if (ps != null) {
+ res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+ }
}
}
@@ -7380,17 +7958,23 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private void deleteTempPackageFiles() {
- FilenameFilter filter = new FilenameFilter() {
+ final FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith("vmdl") && name.endsWith(".tmp");
}
};
- String tmpFilesList[] = mAppInstallDir.list(filter);
- if(tmpFilesList == null) {
+ deleteTempPackageFilesInDirectory(mAppInstallDir, filter);
+ deleteTempPackageFilesInDirectory(mDrmAppPrivateInstallDir, filter);
+ }
+
+ private static final void deleteTempPackageFilesInDirectory(File directory,
+ FilenameFilter filter) {
+ final String[] tmpFilesList = directory.list(filter);
+ if (tmpFilesList == null) {
return;
}
- for(int i = 0; i < tmpFilesList.length; i++) {
- File tmpFile = new File(mAppInstallDir, tmpFilesList[i]);
+ for (int i = 0; i < tmpFilesList.length; i++) {
+ final File tmpFile = new File(directory, tmpFilesList[i]);
tmpFile.delete();
}
}
@@ -7423,10 +8007,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);
@@ -7452,8 +8037,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;
@@ -7468,27 +8052,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, UserId.USER_ALL);
+ extras, null, null, null);
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
- extras, null, null, UserId.USER_ALL);
+ extras, null, null, null);
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
- null, packageName, null, UserId.USER_ALL);
+ null, packageName, null, null);
}
}
// Force a gc here.
@@ -7497,7 +8084,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);
}
}
@@ -7507,29 +8094,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, UserId.USER_ALL);
+ extras, null, null, removedUsers);
if (fullRemove && !replacing) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage,
- extras, null, null, UserId.USER_ALL);
+ extras, null, null, removedUsers);
}
}
- if (removedUid >= 0) {
+ if (removedAppId >= 0) {
sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null,
- UserId.getUserId(removedUid));
+ removedUsers);
}
}
}
@@ -7540,37 +8128,32 @@ public class PackageManagerService extends IPackageManager.Stub {
* make sure this flag is set for partially installed apps. If not its meaningless to
* delete a partially installed application.
*/
- private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo,
+ private void removePackageDataLI(PackageSetting ps, PackageRemovedInfo outInfo,
int flags, boolean writeSettings) {
- String packageName = p.packageName;
- if (outInfo != null) {
- outInfo.removedPackage = packageName;
- }
- removePackageLI(p, (flags&REMOVE_CHATTY) != 0);
+ String packageName = ps.name;
+ removePackageLI(ps, (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 ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
- int retCode = mInstaller.remove(packageName, 0);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove app data or cache directory for package: "
- + packageName + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
- } else {
- // TODO: Kill the processes first
- sUserManager.removePackageForAllUsers(packageName);
+ if (outInfo != null) {
+ outInfo.removedPackage = packageName;
+ outInfo.removedUsers = deletedPs != null
+ ? deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true)
+ : null;
}
- schedulePackageCleaning(packageName);
+ }
+ if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
+ removeDataDirsLI(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);
@@ -7579,7 +8162,7 @@ public class PackageManagerService extends IPackageManager.Stub {
mSettings.updateSharedUserPermsLPw(deletedPs, mGlobalGids);
}
}
- clearPackagePreferredActivitiesLPw(deletedPs.name);
+ clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL);
}
}
// can downgrade to reader
@@ -7593,38 +8176,32 @@ public class PackageManagerService extends IPackageManager.Stub {
/*
* Tries to delete system package.
*/
- private boolean deleteSystemPackageLI(PackageParser.Package p,
+ private boolean deleteSystemPackageLI(PackageSetting newPs,
int flags, PackageRemovedInfo outInfo, boolean writeSettings) {
- ApplicationInfo applicationInfo = p.applicationInfo;
- //applicable for non-partially installed applications only
- if (applicationInfo == null) {
- Slog.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
- return false;
- }
- PackageSetting ps = null;
+ PackageSetting disabledPs = null;
// Confirm if the system package has been updated
// An updated system app can be deleted. This will also have to restore
// the system pkg from system partition
// reader
synchronized (mPackages) {
- ps = mSettings.getDisabledSystemPkgLPr(p.packageName);
+ disabledPs = mSettings.getDisabledSystemPkgLPr(newPs.name);
}
- if (ps == null) {
- Slog.w(TAG, "Attempt to delete unknown system package "+ p.packageName);
+ if (disabledPs == null) {
+ Slog.w(TAG, "Attempt to delete unknown system package "+ newPs.name);
return false;
} else {
Log.i(TAG, "Deleting system pkg from data partition");
}
// Delete the updated package
outInfo.isRemovedPackageSystemUpdate = true;
- if (ps.versionCode < p.mVersionCode) {
+ if (disabledPs.versionCode < newPs.versionCode) {
// 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,
+ boolean ret = deleteInstalledPackageLI(newPs, true, flags, outInfo,
writeSettings);
if (!ret) {
return false;
@@ -7632,17 +8209,18 @@ public class PackageManagerService extends IPackageManager.Stub {
// writer
synchronized (mPackages) {
// Reinstate the old system package
- mSettings.enableSystemPackageLPw(p.packageName);
+ mSettings.enableSystemPackageLPw(newPs.name);
// Remove any native libraries from the upgraded package.
- NativeLibraryHelper.removeNativeBinariesLI(p.applicationInfo.nativeLibraryDir);
+ NativeLibraryHelper.removeNativeBinariesLI(newPs.nativeLibraryPathString);
}
// Install the system package
- PackageParser.Package newPkg = scanPackageLI(ps.codePath,
+ PackageParser.Package newPkg = scanPackageLI(disabledPs.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);
+ Slog.w(TAG, "Failed to restore system package:" + newPs.name
+ + " with error:" + mLastScanError);
return false;
}
// writer
@@ -7657,28 +8235,20 @@ public class PackageManagerService extends IPackageManager.Stub {
return true;
}
- private boolean deleteInstalledPackageLI(PackageParser.Package p,
+ private boolean deleteInstalledPackageLI(PackageSetting ps,
boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo,
boolean writeSettings) {
- ApplicationInfo applicationInfo = p.applicationInfo;
- if (applicationInfo == null) {
- Slog.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
- return false;
- }
if (outInfo != null) {
- outInfo.uid = applicationInfo.uid;
+ outInfo.uid = ps.appId;
}
// Delete package data from internal structures and also remove data if flag is set
- removePackageDataLI(p, outInfo, flags, writeSettings);
+ removePackageDataLI(ps, outInfo, flags, writeSettings);
// Delete application code and resources
if (deleteCodeAndResources) {
- // TODO can pick up from PackageSettings as well
- int installFlags = isExternal(p) ? PackageManager.INSTALL_EXTERNAL : 0;
- installFlags |= isForwardLocked(p) ? PackageManager.INSTALL_FORWARD_LOCK : 0;
- outInfo.args = createInstallArgs(installFlags, applicationInfo.sourceDir,
- applicationInfo.publicSourceDir, applicationInfo.nativeLibraryDir);
+ outInfo.args = createInstallArgs(packageFlagsToInstallFlags(ps), ps.codePathString,
+ ps.resourcePathString, ps.nativeLibraryPathString);
}
return true;
}
@@ -7686,54 +8256,78 @@ 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) {
Slog.w(TAG, "Attempt to delete null packageName.");
return false;
}
- PackageParser.Package p;
+ PackageSetting ps;
boolean dataOnly = false;
+ int removeUser = -1;
+ int appId = -1;
synchronized (mPackages) {
- p = mPackages.get(packageName);
- if (p == null) {
- //this retrieves partially installed apps
- dataOnly = true;
- PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null) {
- Slog.w(TAG, "Package named '" + packageName +"' doesn't exist.");
- return false;
+ ps = mSettings.mPackages.get(packageName);
+ if (ps == null) {
+ Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
+ return false;
+ }
+ if (!isSystemApp(ps) && 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());
}
- p = ps.pkg;
}
}
- 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) {
// Delete application data first
- removePackageDataLI(p, outInfo, flags, writeSettings);
+ removePackageDataLI(ps, outInfo, flags, writeSettings);
return true;
}
- // At this point the package should have ApplicationInfo associated with it
- if (p.applicationInfo == null) {
- Slog.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
- return false;
- }
boolean ret = false;
- if (isSystemApp(p)) {
- Log.i(TAG, "Removing system package:"+p.packageName);
+ if (isSystemApp(ps)) {
+ Log.i(TAG, "Removing system package:" + ps.name);
// When an updated system application is deleted we delete the existing resources as well and
// fall back to existing code in system partition
- ret = deleteSystemPackageLI(p, flags, outInfo, writeSettings);
+ ret = deleteSystemPackageLI(ps, flags, outInfo, writeSettings);
} else {
- Log.i(TAG, "Removing non-system package:"+p.packageName);
+ Log.i(TAG, "Removing non-system package:" + ps.name);
// Kill application pre-emptively especially for apps on sd.
- killApplication(packageName, p.applicationInfo.uid);
- ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo,
+ killApplication(packageName, ps.appId);
+ ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags, outInfo,
writeSettings);
}
return ret;
@@ -7755,7 +8349,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;
@@ -7771,44 +8365,54 @@ 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 UserEnvironment userEnv = new UserEnvironment(curUser);
+ final File externalCacheDir = userEnv
+ .getExternalStorageAppCacheDirectory(packageName);
try {
- conn.mContainerService.clearDirectory(externalMediaDir.toString());
+ conn.mContainerService.clearDirectory(externalCacheDir.toString());
} catch (RemoteException e) {
}
+ if (allData) {
+ final File externalDataDir = userEnv
+ .getExternalStorageAppDataDirectory(packageName);
+ try {
+ conn.mContainerService.clearDirectory(externalDataDir.toString());
+ } catch (RemoteException e) {
+ }
+ final File externalMediaDir = userEnv
+ .getExternalStorageAppMediaDirectory(packageName);
+ try {
+ conn.mContainerService.clearDirectory(externalMediaDir.toString());
+ } catch (RemoteException e) {
+ }
+ }
+ } finally {
+ mContext.unbindService(conn);
}
- } finally {
- mContext.unbindService(conn);
}
}
}
@@ -7818,7 +8422,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final IPackageDataObserver observer, final int userId) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CLEAR_APP_USER_DATA, null);
- checkValidCaller(Binder.getCallingUid(), userId);
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "clear application data");
// Queue up an async operation since the package deletion may take a little while.
mHandler.post(new Runnable() {
public void run() {
@@ -7827,7 +8431,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)
@@ -7893,7 +8497,7 @@ public class PackageManagerService extends IPackageManager.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DELETE_CACHE_FILES, null);
// Queue up an async operation since the package deletion may take a little while.
- final int userId = UserId.getCallingUserId();
+ final int userId = UserHandle.getCallingUserId();
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
@@ -7901,7 +8505,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);
@@ -7941,12 +8545,12 @@ public class PackageManagerService extends IPackageManager.Stub {
return true;
}
- public void getPackageSizeInfo(final String packageName,
+ public void getPackageSizeInfo(final String packageName, int userHandle,
final IPackageStatsObserver observer) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.GET_PACKAGE_SIZE, null);
- PackageStats stats = new PackageStats(packageName);
+ PackageStats stats = new PackageStats(packageName, userHandle);
/*
* Queue up an async operation since the package measurement may take a
@@ -7957,7 +8561,8 @@ public class PackageManagerService extends IPackageManager.Stub {
mHandler.sendMessage(msg);
}
- private boolean getPackageSizeInfoLI(String packageName, PackageStats pStats) {
+ private boolean getPackageSizeInfoLI(String packageName, int userHandle,
+ PackageStats pStats) {
if (packageName == null) {
Slog.w(TAG, "Attempt to get size of null packageName.");
return false;
@@ -7994,7 +8599,7 @@ public class PackageManagerService extends IPackageManager.Stub {
publicSrcDir = applicationInfo.publicSourceDir;
}
}
- int res = mInstaller.getSizeInfo(packageName, p.mPath, publicSrcDir,
+ int res = mInstaller.getSizeInfo(packageName, userHandle, p.mPath, publicSrcDir,
asecPath, pStats);
if (res < 0) {
return false;
@@ -8046,26 +8651,28 @@ public class PackageManagerService extends IPackageManager.Stub {
}
public void addPreferredActivity(IntentFilter filter, int match,
- ComponentName[] set, ComponentName activity) {
+ ComponentName[] set, ComponentName activity, int userId) {
// writer
+ int callingUid = Binder.getCallingUid();
+ enforceCrossUserPermission(callingUid, userId, true, "add preferred activity");
synchronized (mPackages) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- if (getUidTargetSdkVersionLockedLPr(Binder.getCallingUid())
+ if (getUidTargetSdkVersionLockedLPr(callingUid)
< Build.VERSION_CODES.FROYO) {
Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
- + Binder.getCallingUid());
+ + callingUid);
return;
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
}
-
- Slog.i(TAG, "Adding preferred activity " + activity + ":");
+
+ Slog.i(TAG, "Adding preferred activity " + activity + " for user " + userId + " :");
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
mSettings.mPreferredActivities.addFilter(
- new PreferredActivity(filter, match, set, activity));
+ new PreferredActivity(filter, match, set, activity, userId));
scheduleWriteSettingsLocked();
}
}
@@ -8101,13 +8708,15 @@ public class PackageManagerService extends IPackageManager.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
}
-
+
+ final int callingUserId = UserHandle.getCallingUserId();
ArrayList<PreferredActivity> removed = null;
Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
String action = filter.getAction(0);
String category = filter.getCategory(0);
while (it.hasNext()) {
PreferredActivity pa = it.next();
+ if (pa.mUserId != callingUserId) continue;
if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) {
if (removed == null) {
removed = new ArrayList<PreferredActivity>();
@@ -8123,7 +8732,7 @@ public class PackageManagerService extends IPackageManager.Stub {
mSettings.mPreferredActivities.removeFilter(pa);
}
}
- addPreferredActivity(filter, match, set, activity);
+ addPreferredActivity(filter, match, set, activity, callingUserId);
}
}
@@ -8147,17 +8756,21 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- if (clearPackagePreferredActivitiesLPw(packageName)) {
+ if (clearPackagePreferredActivitiesLPw(packageName, UserHandle.getCallingUserId())) {
scheduleWriteSettingsLocked();
}
}
}
- boolean clearPackagePreferredActivitiesLPw(String packageName) {
+ /** This method takes a specific user id as well as UserHandle.USER_ALL. */
+ boolean clearPackagePreferredActivitiesLPw(String packageName, int userId) {
ArrayList<PreferredActivity> removed = null;
Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
while (it.hasNext()) {
PreferredActivity pa = it.next();
+ if (userId != UserHandle.USER_ALL && pa.mUserId != userId) {
+ continue;
+ }
if (pa.mPref.mComponent.getPackageName().equals(packageName)) {
if (removed == null) {
removed = new ArrayList<PreferredActivity>();
@@ -8179,11 +8792,15 @@ public class PackageManagerService extends IPackageManager.Stub {
List<ComponentName> outActivities, String packageName) {
int num = 0;
+ final int userId = UserHandle.getCallingUserId();
// reader
synchronized (mPackages) {
final Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
while (it.hasNext()) {
final PreferredActivity pa = it.next();
+ if (pa.mUserId != userId) {
+ continue;
+ }
if (packageName == null
|| pa.mPref.mComponent.getPackageName().equals(packageName)) {
if (outFilters != null) {
@@ -8227,7 +8844,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final int uid = Binder.getCallingUid();
final int permission = mContext.checkCallingPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
- checkValidCaller(uid, userId);
+ enforceCrossUserPermission(uid, userId, false, "set enabled");
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
boolean sendNow = false;
boolean isApp = (className == null);
@@ -8248,7 +8865,7 @@ public class PackageManagerService extends IPackageManager.Stub {
+ "/" + className);
}
// Allow root and verify that userId is not being specified by a different user
- if (!allowedByPermission && !UserId.isSameApp(uid, pkgSetting.appId)) {
+ if (!allowedByPermission && !UserHandle.isSameApp(uid, pkgSetting.appId)) {
throw new SecurityException(
"Permission Denial: attempt to change component state from pid="
+ Binder.getCallingPid()
@@ -8297,7 +8914,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
mSettings.writePackageRestrictionsLPr(userId);
- packageUid = UserId.getUid(userId, pkgSetting.appId);
+ packageUid = UserHandle.getUid(userId, pkgSetting.appId);
components = mPendingBroadcasts.get(packageName);
final boolean newPackage = components == null;
if (newPackage) {
@@ -8346,7 +8963,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,
- UserId.getUserId(packageUid));
+ new int[] {UserHandle.getUserId(packageUid)});
}
public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
@@ -8355,7 +8972,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final int permission = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
- checkValidCaller(uid, userId);
+ enforceCrossUserPermission(uid, userId, true, "stop package");
// writer
synchronized (mPackages) {
if (mSettings.setPackageStoppedStateLPw(packageName, stopped, allowedByPermission,
@@ -8376,7 +8993,7 @@ public class PackageManagerService extends IPackageManager.Stub {
public int getApplicationEnabledSetting(String packageName, int userId) {
if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
int uid = Binder.getCallingUid();
- checkValidCaller(uid, userId);
+ enforceCrossUserPermission(uid, userId, false, "get enabled");
// reader
synchronized (mPackages) {
return mSettings.getApplicationEnabledSettingLPr(packageName, userId);
@@ -8387,7 +9004,7 @@ public class PackageManagerService extends IPackageManager.Stub {
public int getComponentEnabledSetting(ComponentName componentName, int userId) {
if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
int uid = Binder.getCallingUid();
- checkValidCaller(uid, userId);
+ enforceCrossUserPermission(uid, userId, false, "get component enabled");
// reader
synchronized (mPackages) {
return mSettings.getComponentEnabledSettingLPr(componentName, userId);
@@ -8951,7 +9568,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");
@@ -8972,7 +9589,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, UserId.USER_ALL);
+ sendPackageBroadcast(action, null, extras, null, finishedReceiver, null);
}
}
@@ -9017,7 +9634,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) {
/*
@@ -9126,8 +9743,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 {
@@ -9151,7 +9768,8 @@ public class PackageManagerService extends IPackageManager.Stub {
if (pkgList.size() > 0) {
sendResourcesChangedBroadcast(false, pkgList, uidArr, new IIntentReceiver.Stub() {
public void performReceive(Intent intent, int resultCode, String data,
- Bundle extras, boolean ordered, boolean sticky) throws RemoteException {
+ Bundle extras, boolean ordered, boolean sticky,
+ int sendingUser) throws RemoteException {
Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
reportStatus ? 1 : 0, 1, keys);
mHandler.sendMessage(msg);
@@ -9164,9 +9782,12 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ /** Binder call */
+ @Override
public void movePackage(final String packageName, final IPackageMoveObserver observer,
final int flags) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
+ UserHandle user = new UserHandle(UserHandle.getCallingUserId());
int returnCode = PackageManager.MOVE_SUCCEEDED;
int currFlags = 0;
int newFlags = 0;
@@ -9217,14 +9838,15 @@ public class PackageManagerService extends IPackageManager.Stub {
* anyway.
*/
if (returnCode != PackageManager.MOVE_SUCCEEDED) {
- processPendingMove(new MoveParams(null, observer, 0, packageName, null, -1),
+ processPendingMove(new MoveParams(null, observer, 0, packageName,
+ null, -1, user),
returnCode);
} else {
Message msg = mHandler.obtainMessage(INIT_COPY);
InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir,
pkg.applicationInfo.publicSourceDir, pkg.applicationInfo.nativeLibraryDir);
MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName,
- pkg.applicationInfo.dataDir, pkg.applicationInfo.uid);
+ pkg.applicationInfo.dataDir, pkg.applicationInfo.uid, user);
msg.obj = mp;
mHandler.sendMessage(msg);
}
@@ -9288,31 +9910,26 @@ public class PackageManagerService extends IPackageManager.Stub {
final String newNativePath = mp.targetArgs
.getNativeLibraryPath();
- try {
- final File newNativeDir = new File(newNativePath);
+ final File newNativeDir = new File(newNativePath);
- final String libParentDir = newNativeDir.getParentFile()
- .getCanonicalPath();
- if (newNativeDir.getParentFile().getCanonicalPath()
- .equals(pkg.applicationInfo.dataDir)) {
- if (mInstaller
- .unlinkNativeLibraryDirectory(pkg.applicationInfo.dataDir) < 0) {
+ if (!isForwardLocked(pkg) && !isExternal(pkg)) {
+ synchronized (mInstallLock) {
+ if (mInstaller.linkNativeLibraryDirectory(
+ pkg.applicationInfo.dataDir, newNativePath) < 0) {
returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
- } else {
- NativeLibraryHelper.copyNativeBinariesIfNeededLI(
- new File(newCodePath), newNativeDir);
}
- } else {
+ }
+ NativeLibraryHelper.copyNativeBinariesIfNeededLI(new File(
+ newCodePath), newNativeDir);
+ } else {
+ synchronized (mInstallLock) {
if (mInstaller.linkNativeLibraryDirectory(
pkg.applicationInfo.dataDir, newNativePath) < 0) {
returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
}
}
- } catch (IOException e) {
- returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
}
-
if (returnCode == PackageManager.MOVE_SUCCEEDED) {
pkg.mPath = newCodePath;
// Move dex files around
@@ -9415,48 +10032,37 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageHelper.APP_INSTALL_AUTO);
}
- public UserInfo createUser(String name, int flags) {
- // TODO(kroot): Add a real permission for creating users
- enforceSystemOrRoot("Only the system can create users");
-
- UserInfo userInfo = sUserManager.createUser(name, flags);
- if (userInfo != null) {
- Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
- addedIntent.putExtra(Intent.EXTRA_USERID, userInfo.id);
- mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS);
- }
- return userInfo;
- }
-
- public boolean removeUser(int userId) {
- // TODO(kroot): Add a real permission for removing users
- enforceSystemOrRoot("Only the system can remove users");
-
- if (userId == 0 || !sUserManager.exists(userId)) {
- return false;
+ /** Called by UserManagerService */
+ void cleanUpUserLILPw(int userHandle) {
+ // Disable all the packages for the user first
+ Set<Entry<String, PackageSetting>> entries = mSettings.mPackages.entrySet();
+ for (Entry<String, PackageSetting> entry : entries) {
+ entry.getValue().removeUser(userHandle);
}
-
- cleanUpUser(userId);
-
- if (sUserManager.removeUser(userId)) {
- // Let other services shutdown any activity
- Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
- addedIntent.putExtra(Intent.EXTRA_USERID, userId);
- mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS);
+ if (mDirtyUsers.remove(userHandle));
+ mSettings.removeUserLPr(userHandle);
+ if (mInstaller != null) {
+ // Technically, we shouldn't be doing this with the package lock
+ // held. However, this is very rare, and there is already so much
+ // other disk I/O going on, that we'll let it slide for now.
+ mInstaller.removeUserDataDirs(userHandle);
}
- sUserManager.removePackageFolders(userId);
- return true;
}
- private void cleanUpUser(int userId) {
- // Disable all the packages for the user first
- synchronized (mPackages) {
- Set<Entry<String, PackageSetting>> entries = mSettings.mPackages.entrySet();
- for (Entry<String, PackageSetting> entry : entries) {
- entry.getValue().removeUser(userId);
+ /** Called by UserManagerService */
+ void createNewUserLILPw(int userHandle, File path) {
+ if (mInstaller != null) {
+ path.mkdir();
+ FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+ | FileUtils.S_IXOTH, -1, -1);
+ for (PackageSetting ps : mSettings.mPackages.values()) {
+ // Only system apps are initially installed.
+ ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);
+ // Need to create a data directory for all apps under this user.
+ mInstaller.createUserData(ps.name,
+ UserHandle.getUid(userHandle, ps.appId), userHandle);
}
- if (mDirtyUsers.remove(userId));
- mSettings.removeUserLPr(userId);
+ mSettings.writePackageRestrictionsLPr(userHandle);
}
}
@@ -9472,24 +10078,6 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
- public List<UserInfo> getUsers() {
- enforceSystemOrRoot("Only the system can query users");
- return sUserManager.getUsers();
- }
-
- @Override
- public UserInfo getUser(int userId) {
- enforceSystemOrRoot("Only the system can remove users");
- return sUserManager.getUser(userId);
- }
-
- @Override
- public void updateUserName(int userId, String name) {
- enforceSystemOrRoot("Only the system can rename users");
- sUserManager.updateUserName(userId, name);
- }
-
- @Override
public void setPermissionEnforced(String permission, boolean enforced) {
mContext.enforceCallingOrSelfPermission(GRANT_REVOKE_PERMISSIONS, null);
if (READ_EXTERNAL_STORAGE.equals(permission)) {
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java
index 56f2166..d8f7345 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[] queryInstalledUsers(int[] users, boolean installed) {
+ int num = 0;
+ for (int user : users) {
+ if (getInstalled(user) == installed) {
+ num++;
+ }
+ }
+ int[] res = new int[num];
+ num = 0;
+ for (int user : users) {
+ if (getInstalled(user) == installed) {
+ 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/PackageVerificationState.java b/services/java/com/android/server/pm/PackageVerificationState.java
index e5b89c1..3214e88 100644
--- a/services/java/com/android/server/pm/PackageVerificationState.java
+++ b/services/java/com/android/server/pm/PackageVerificationState.java
@@ -43,6 +43,8 @@ class PackageVerificationState {
private boolean mRequiredVerificationPassed;
+ private boolean mExtendedTimeout;
+
/**
* Create a new package verification state where {@code requiredVerifierUid}
* is the user ID for the package that must reply affirmative before things
@@ -55,6 +57,7 @@ class PackageVerificationState {
mRequiredVerifierUid = requiredVerifierUid;
mArgs = args;
mSufficientVerifierUids = new SparseBooleanArray();
+ mExtendedTimeout = false;
}
public InstallArgs getInstallArgs() {
@@ -146,4 +149,22 @@ class PackageVerificationState {
return true;
}
+
+ /**
+ * Extend the timeout for this Package to be verified.
+ */
+ public void extendTimeout() {
+ if (!mExtendedTimeout) {
+ mExtendedTimeout = true;
+ }
+ }
+
+ /**
+ * Returns whether the timeout was extended for verification.
+ *
+ * @return {@code true} if a timeout was already extended.
+ */
+ public boolean timeoutExtended() {
+ return mExtendedTimeout;
+ }
}
diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/java/com/android/server/pm/PreferredActivity.java
index b100eb1..5539e84 100644
--- a/services/java/com/android/server/pm/PreferredActivity.java
+++ b/services/java/com/android/server/pm/PreferredActivity.java
@@ -33,22 +33,38 @@ class PreferredActivity extends IntentFilter implements PreferredComponent.Callb
private static final String TAG = "PreferredActivity";
private static final boolean DEBUG_FILTERS = false;
+ static final String ATTR_USER_ID = "userId";
final PreferredComponent mPref;
+ final int mUserId;
PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) {
+ this(filter, match, set, activity, 0);
+ }
+
+ PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity,
+ int userId) {
super(filter);
+ mUserId = userId;
mPref = new PreferredComponent(this, match, set, activity);
}
PreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException {
+ String userIdString = parser.getAttributeValue(null, ATTR_USER_ID);
+ if (userIdString != null && userIdString.length() > 0) {
+ mUserId = Integer.parseInt(userIdString);
+ } else {
+ // Old format with no userId specified - assume primary user
+ mUserId = 0;
+ }
mPref = new PreferredComponent(this, parser);
}
public void writeToXml(XmlSerializer serializer) throws IOException {
+ serializer.attribute(null, ATTR_USER_ID, Integer.toString(mUserId));
mPref.writeToXml(serializer);
serializer.startTag(null, "filter");
- super.writeToXml(serializer);
+ super.writeToXml(serializer);
serializer.endTag(null, "filter");
}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 120b650..b075da3 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -32,23 +32,24 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
-import android.app.AppGlobals;
import android.content.ComponentName;
+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;
import android.os.FileUtils;
import android.os.Process;
-import android.os.RemoteException;
-import android.os.UserId;
+import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -79,6 +80,7 @@ final class Settings {
private static final String TAG = "PackageSettings";
private static final boolean DEBUG_STOPPED = false;
+ private static final boolean DEBUG_MU = false;
private static final String TAG_READ_EXTERNAL_STORAGE = "read-external-storage";
private static final String ATTR_ENFORCEMENT = "enforcement";
@@ -90,9 +92,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;
@@ -121,6 +126,10 @@ final class Settings {
final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities =
new IntentResolver<PreferredActivity, PreferredActivity>() {
@Override
+ protected PreferredActivity[] newArray(int size) {
+ return new PreferredActivity[size];
+ }
+ @Override
protected String packageForFilter(PreferredActivity filter) {
return filter.mPref.mComponent.getPackageName();
}
@@ -150,7 +159,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
@@ -169,12 +179,15 @@ final class Settings {
*/
private final ArrayList<PendingPackage> mPendingPackages = new ArrayList<PendingPackage>();
+ private final Context mContext;
+
private final File mSystemDir;
- Settings() {
- this(Environment.getDataDirectory());
+ Settings(Context context) {
+ this(context, Environment.getDataDirectory());
}
- Settings(File dataDir) {
+ Settings(Context context, File dataDir) {
+ mContext = context;
mSystemDir = new File(dataDir, "system");
mSystemDir.mkdirs();
FileUtils.setPermissions(mSystemDir.toString(),
@@ -191,10 +204,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;
}
@@ -355,7 +369,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)) {
@@ -398,11 +413,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,
@@ -436,8 +446,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);
}
}
@@ -463,12 +485,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
@@ -489,6 +509,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;
}
@@ -527,6 +566,10 @@ final class Settings {
if (p.signatures.mSignatures == null) {
p.signatures.assignSignatures(pkg.mSignatures);
}
+ // Update flags if needed.
+ if (pkg.applicationInfo.flags != p.pkgFlags) {
+ p.pkgFlags = pkg.applicationInfo.flags;
+ }
// If this app defines a shared user id initialize
// the shared user signatures as well.
if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
@@ -704,13 +747,12 @@ final class Settings {
}
private File getUserPackagesStateFile(int userId) {
- return new File(mSystemDir,
- "users/" + userId + "/package-restrictions.xml");
+ return new File(Environment.getUserSystemDirectory(userId), "package-restrictions.xml");
}
private File getUserPackagesStateBackupFile(int userId) {
- return new File(mSystemDir,
- "users/" + userId + "/package-restrictions-backup.xml");
+ return new File(Environment.getUserSystemDirectory(userId),
+ "package-restrictions-backup.xml");
}
void writeAllUsersPackageRestrictionsLPr() {
@@ -735,6 +777,9 @@ final class Settings {
}
void readPackageRestrictionsLPr(int userId) {
+ if (DEBUG_MU) {
+ Log.i(TAG, "Reading package restrictions for user=" + userId);
+ }
FileInputStream str = null;
File userPackagesStateFile = getUserPackagesStateFile(userId);
File backupFile = getUserPackagesStateBackupFile(userId);
@@ -766,10 +811,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;
}
@@ -811,17 +860,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
@@ -833,13 +886,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());
@@ -864,7 +918,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;
@@ -879,6 +933,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);
}
}
@@ -887,6 +944,9 @@ final class Settings {
}
void writePackageRestrictionsLPr(int userId) {
+ if (DEBUG_MU) {
+ Log.i(TAG, "Writing package restrictions for user=" + userId);
+ }
// Keep the old stopped packages around until we know the new ones have
// been successfully written.
File userPackagesStateFile = getUserPackagesStateFile(userId);
@@ -921,40 +981,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);
- HashSet<String> enabledComponents = pkg.getEnabledComponents(userId);
- HashSet<String> disabledComponents = pkg.getDisabledComponents(userId);
+ if (DEBUG_MU) Log.i(TAG, " pkg=" + pkg.name + ", state=" + ustate.enabled);
- if (stopped) {
+ 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);
@@ -1194,9 +1258,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(j);
+ 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");
+ }
}
}
@@ -1452,6 +1524,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()) {
@@ -1529,8 +1612,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");
@@ -1580,7 +1676,24 @@ final class Settings {
mReadMessages.append("Error reading: " + e.toString());
PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
Log.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
+ }
+ if (mBackupStoppedPackagesFilename.exists()
+ || mStoppedPackagesFilename.exists()) {
+ // Read old file
+ readStoppedLPw();
+ mBackupStoppedPackagesFilename.delete();
+ mStoppedPackagesFilename.delete();
+ // Migrate to new file format
+ writePackageRestrictionsLPr(0);
+ } else {
+ if (users == null) {
+ readPackageRestrictionsLPr(0);
+ } else {
+ for (UserInfo user : users) {
+ readPackageRestrictionsLPr(user.id);
+ }
+ }
}
final int N = mPendingPackages.size();
@@ -1590,7 +1703,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);
@@ -1624,23 +1738,6 @@ final class Settings {
}
}
- if (mBackupStoppedPackagesFilename.exists()
- || mStoppedPackagesFilename.exists()) {
- // Read old file
- readStoppedLPw();
- mBackupStoppedPackagesFilename.delete();
- mStoppedPackagesFilename.delete();
- // Migrate to new file format
- writePackageRestrictionsLPr(0);
- } else {
- if (users == null) {
- readPackageRestrictionsLPr(0);
- } else {
- for (UserInfo user : users) {
- readPackageRestrictionsLPr(user.id);
- }
- }
- }
mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, "
+ mSharedUsers.size() + " shared uids\n");
@@ -2276,6 +2373,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;
@@ -2286,24 +2387,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;
@@ -2337,7 +2440,7 @@ final class Settings {
boolean setPackageStoppedStateLPw(String packageName, boolean stopped,
boolean allowedByPermission, int uid, int userId) {
- int appId = UserId.getAppId(uid);
+ int appId = UserHandle.getAppId(uid);
final PackageSetting pkgSetting = mPackages.get(packageName);
if (pkgSetting == null) {
throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -2362,7 +2465,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);
}
@@ -2374,9 +2477,7 @@ final class Settings {
private List<UserInfo> getAllUsers() {
long id = Binder.clearCallingIdentity();
try {
- return AppGlobals.getPackageManager().getUsers();
- } catch (RemoteException re) {
- // Local to system process, shouldn't happen
+ return UserManagerService.getInstance().getUsers();
} catch (NullPointerException npe) {
// packagemanager not yet initialized
} finally {
@@ -2413,7 +2514,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",
};
@@ -2505,8 +2605,8 @@ final class Settings {
first = false;
pw.print("anyDensity");
}
+ pw.println("]");
}
- pw.println("]");
pw.print(" timeStamp=");
date.setTime(ps.timeStamp);
pw.println(sdf.format(date));
@@ -2520,25 +2620,31 @@ final class Settings {
pw.print(" installerPackageName="); pw.println(ps.installerPackageName);
}
pw.print(" signatures="); pw.println(ps.signatures);
- pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
- pw.print(" haveGids="); pw.println(ps.haveGids);
- pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
- pw.print(" installStatus="); pw.print(ps.installStatus);
+ pw.print(" permissionsFixed="); pw.println(ps.permissionsFixed);
+ pw.print(" haveGids="); pw.println(ps.haveGids);
+ pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
+ 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/ShutdownThread.java b/services/java/com/android/server/pm/ShutdownThread.java
deleted file mode 100644
index 3675d41..0000000
--- a/services/java/com/android/server/pm/ShutdownThread.java
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
- * Copyright (C) 2008 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 com.android.server.pm;
-
-import android.app.ActivityManagerNative;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.IActivityManager;
-import android.app.ProgressDialog;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.IBluetooth;
-import android.nfc.NfcAdapter;
-import android.nfc.INfcAdapter;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.Vibrator;
-import android.os.SystemVibrator;
-import android.os.storage.IMountService;
-import android.os.storage.IMountShutdownObserver;
-
-import com.android.internal.telephony.ITelephony;
-import com.android.server.PowerManagerService;
-
-import android.util.Log;
-import android.view.WindowManager;
-
-public final class ShutdownThread extends Thread {
- // constants
- private static final String TAG = "ShutdownThread";
- private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500;
- // maximum time we wait for the shutdown broadcast before going on.
- private static final int MAX_BROADCAST_TIME = 10*1000;
- private static final int MAX_SHUTDOWN_WAIT_TIME = 20*1000;
- private static final int MAX_RADIO_WAIT_TIME = 12*1000;
-
- // length of vibration before shutting down
- private static final int SHUTDOWN_VIBRATE_MS = 500;
-
- // state tracking
- private static Object sIsStartedGuard = new Object();
- private static boolean sIsStarted = false;
-
- private static boolean mReboot;
- private static boolean mRebootSafeMode;
- private static String mRebootReason;
-
- // Provides shutdown assurance in case the system_server is killed
- public static final String SHUTDOWN_ACTION_PROPERTY = "sys.shutdown.requested";
-
- // Indicates whether we are rebooting into safe mode
- public static final String REBOOT_SAFEMODE_PROPERTY = "persist.sys.safemode";
-
- // static instance of this thread
- private static final ShutdownThread sInstance = new ShutdownThread();
-
- private final Object mActionDoneSync = new Object();
- private boolean mActionDone;
- private Context mContext;
- private PowerManager mPowerManager;
- private PowerManager.WakeLock mCpuWakeLock;
- private PowerManager.WakeLock mScreenWakeLock;
- private Handler mHandler;
-
- private static AlertDialog sConfirmDialog;
-
- private ShutdownThread() {
- }
-
- /**
- * Request a clean shutdown, waiting for subsystems to clean up their
- * state etc. Must be called from a Looper thread in which its UI
- * is shown.
- *
- * @param context Context used to display the shutdown progress dialog.
- * @param confirm true if user confirmation is needed before shutting down.
- */
- public static void shutdown(final Context context, boolean confirm) {
- mReboot = false;
- mRebootSafeMode = false;
- shutdownInner(context, confirm);
- }
-
- static void shutdownInner(final Context context, boolean confirm) {
- // ensure that only one thread is trying to power down.
- // any additional calls are just returned
- synchronized (sIsStartedGuard) {
- if (sIsStarted) {
- Log.d(TAG, "Request to shutdown already running, returning.");
- return;
- }
- }
-
- final int longPressBehavior = context.getResources().getInteger(
- com.android.internal.R.integer.config_longPressOnPowerBehavior);
- final int resourceId = mRebootSafeMode
- ? com.android.internal.R.string.reboot_safemode_confirm
- : (longPressBehavior == 2
- ? com.android.internal.R.string.shutdown_confirm_question
- : com.android.internal.R.string.shutdown_confirm);
-
- Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
-
- if (confirm) {
- final CloseDialogReceiver closer = new CloseDialogReceiver(context);
- if (sConfirmDialog != null) {
- sConfirmDialog.dismiss();
- }
- sConfirmDialog = new AlertDialog.Builder(context)
- .setTitle(mRebootSafeMode
- ? com.android.internal.R.string.reboot_safemode_title
- : com.android.internal.R.string.power_off)
- .setMessage(resourceId)
- .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- beginShutdownSequence(context);
- }
- })
- .setNegativeButton(com.android.internal.R.string.no, null)
- .create();
- closer.dialog = sConfirmDialog;
- sConfirmDialog.setOnDismissListener(closer);
- sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- sConfirmDialog.show();
- } else {
- beginShutdownSequence(context);
- }
- }
-
- private static class CloseDialogReceiver extends BroadcastReceiver
- implements DialogInterface.OnDismissListener {
- private Context mContext;
- public Dialog dialog;
-
- CloseDialogReceiver(Context context) {
- mContext = context;
- IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- context.registerReceiver(this, filter);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- dialog.cancel();
- }
-
- public void onDismiss(DialogInterface unused) {
- mContext.unregisterReceiver(this);
- }
- }
-
- /**
- * Request a clean shutdown, waiting for subsystems to clean up their
- * state etc. Must be called from a Looper thread in which its UI
- * is shown.
- *
- * @param context Context used to display the shutdown progress dialog.
- * @param reason code to pass to the kernel (e.g. "recovery"), or null.
- * @param confirm true if user confirmation is needed before shutting down.
- */
- public static void reboot(final Context context, String reason, boolean confirm) {
- mReboot = true;
- mRebootSafeMode = false;
- mRebootReason = reason;
- shutdownInner(context, confirm);
- }
-
- /**
- * Request a reboot into safe mode. Must be called from a Looper thread in which its UI
- * is shown.
- *
- * @param context Context used to display the shutdown progress dialog.
- * @param confirm true if user confirmation is needed before shutting down.
- */
- public static void rebootSafeMode(final Context context, boolean confirm) {
- mReboot = true;
- mRebootSafeMode = true;
- mRebootReason = null;
- shutdownInner(context, confirm);
- }
-
- private static void beginShutdownSequence(Context context) {
- synchronized (sIsStartedGuard) {
- if (sIsStarted) {
- Log.d(TAG, "Shutdown sequence already running, returning.");
- return;
- }
- sIsStarted = true;
- }
-
- // throw up an indeterminate system dialog to indicate radio is
- // shutting down.
- ProgressDialog pd = new ProgressDialog(context);
- pd.setTitle(context.getText(com.android.internal.R.string.power_off));
- pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
- pd.setIndeterminate(true);
- pd.setCancelable(false);
- pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-
- pd.show();
-
- sInstance.mContext = context;
- sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-
- // make sure we never fall asleep again
- sInstance.mCpuWakeLock = null;
- try {
- sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
- PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
- sInstance.mCpuWakeLock.setReferenceCounted(false);
- sInstance.mCpuWakeLock.acquire();
- } catch (SecurityException e) {
- Log.w(TAG, "No permission to acquire wake lock", e);
- sInstance.mCpuWakeLock = null;
- }
-
- // also make sure the screen stays on for better user experience
- sInstance.mScreenWakeLock = null;
- if (sInstance.mPowerManager.isScreenOn()) {
- try {
- sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
- PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
- sInstance.mScreenWakeLock.setReferenceCounted(false);
- sInstance.mScreenWakeLock.acquire();
- } catch (SecurityException e) {
- Log.w(TAG, "No permission to acquire wake lock", e);
- sInstance.mScreenWakeLock = null;
- }
- }
-
- // start the thread that initiates shutdown
- sInstance.mHandler = new Handler() {
- };
- sInstance.start();
- }
-
- void actionDone() {
- synchronized (mActionDoneSync) {
- mActionDone = true;
- mActionDoneSync.notifyAll();
- }
- }
-
- /**
- * Makes sure we handle the shutdown gracefully.
- * Shuts off power regardless of radio and bluetooth state if the alloted time has passed.
- */
- public void run() {
- BroadcastReceiver br = new BroadcastReceiver() {
- @Override public void onReceive(Context context, Intent intent) {
- // We don't allow apps to cancel this, so ignore the result.
- actionDone();
- }
- };
-
- /*
- * Write a system property in case the system_server reboots before we
- * get to the actual hardware restart. If that happens, we'll retry at
- * the beginning of the SystemServer startup.
- */
- {
- String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
- SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
- }
-
- /*
- * If we are rebooting into safe mode, write a system property
- * indicating so.
- */
- if (mRebootSafeMode) {
- SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
- }
-
- Log.i(TAG, "Sending shutdown broadcast...");
-
- // First send the high-level shut down broadcast.
- mActionDone = false;
- mContext.sendOrderedBroadcast(new Intent(Intent.ACTION_SHUTDOWN), null,
- br, mHandler, 0, null, null);
-
- final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
- synchronized (mActionDoneSync) {
- while (!mActionDone) {
- long delay = endTime - SystemClock.elapsedRealtime();
- if (delay <= 0) {
- Log.w(TAG, "Shutdown broadcast timed out");
- break;
- }
- try {
- mActionDoneSync.wait(delay);
- } catch (InterruptedException e) {
- }
- }
- }
-
- Log.i(TAG, "Shutting down activity manager...");
-
- final IActivityManager am =
- ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
- if (am != null) {
- try {
- am.shutdown(MAX_BROADCAST_TIME);
- } catch (RemoteException e) {
- }
- }
-
- // Shutdown radios.
- shutdownRadios(MAX_RADIO_WAIT_TIME);
-
- // Shutdown MountService to ensure media is in a safe state
- IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
- public void onShutDownComplete(int statusCode) throws RemoteException {
- Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
- actionDone();
- }
- };
-
- Log.i(TAG, "Shutting down MountService");
-
- // Set initial variables and time out time.
- mActionDone = false;
- final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
- synchronized (mActionDoneSync) {
- try {
- final IMountService mount = IMountService.Stub.asInterface(
- ServiceManager.checkService("mount"));
- if (mount != null) {
- mount.shutdown(observer);
- } else {
- Log.w(TAG, "MountService unavailable for shutdown");
- }
- } catch (Exception e) {
- Log.e(TAG, "Exception during MountService shutdown", e);
- }
- while (!mActionDone) {
- long delay = endShutTime - SystemClock.elapsedRealtime();
- if (delay <= 0) {
- Log.w(TAG, "Shutdown wait timed out");
- break;
- }
- try {
- mActionDoneSync.wait(delay);
- } catch (InterruptedException e) {
- }
- }
- }
-
- rebootOrShutdown(mReboot, mRebootReason);
- }
-
- private void shutdownRadios(int timeout) {
- // If a radio is wedged, disabling it may hang so we do this work in another thread,
- // just in case.
- final long endTime = SystemClock.elapsedRealtime() + timeout;
- final boolean[] done = new boolean[1];
- Thread t = new Thread() {
- public void run() {
- boolean nfcOff;
- boolean bluetoothOff;
- boolean radioOff;
-
- final INfcAdapter nfc =
- INfcAdapter.Stub.asInterface(ServiceManager.checkService("nfc"));
- final ITelephony phone =
- ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
- final IBluetooth bluetooth =
- IBluetooth.Stub.asInterface(ServiceManager.checkService(
- BluetoothAdapter.BLUETOOTH_SERVICE));
-
- try {
- nfcOff = nfc == null ||
- nfc.getState() == NfcAdapter.STATE_OFF;
- if (!nfcOff) {
- Log.w(TAG, "Turning off NFC...");
- nfc.disable(false); // Don't persist new state
- }
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException during NFC shutdown", ex);
- nfcOff = true;
- }
-
- try {
- bluetoothOff = bluetooth == null ||
- bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
- if (!bluetoothOff) {
- Log.w(TAG, "Disabling Bluetooth...");
- bluetooth.disable(false); // disable but don't persist new state
- }
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
- bluetoothOff = true;
- }
-
- try {
- radioOff = phone == null || !phone.isRadioOn();
- if (!radioOff) {
- Log.w(TAG, "Turning off radio...");
- phone.setRadio(false);
- }
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException during radio shutdown", ex);
- radioOff = true;
- }
-
- Log.i(TAG, "Waiting for NFC, Bluetooth and Radio...");
-
- while (SystemClock.elapsedRealtime() < endTime) {
- if (!bluetoothOff) {
- try {
- bluetoothOff =
- bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
- bluetoothOff = true;
- }
- if (bluetoothOff) {
- Log.i(TAG, "Bluetooth turned off.");
- }
- }
- if (!radioOff) {
- try {
- radioOff = !phone.isRadioOn();
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException during radio shutdown", ex);
- radioOff = true;
- }
- if (radioOff) {
- Log.i(TAG, "Radio turned off.");
- }
- }
- if (!nfcOff) {
- try {
- nfcOff = nfc.getState() == NfcAdapter.STATE_OFF;
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException during NFC shutdown", ex);
- nfcOff = true;
- }
- if (radioOff) {
- Log.i(TAG, "NFC turned off.");
- }
- }
-
- if (radioOff && bluetoothOff && nfcOff) {
- Log.i(TAG, "NFC, Radio and Bluetooth shutdown complete.");
- done[0] = true;
- break;
- }
- SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);
- }
- }
- };
-
- t.start();
- try {
- t.join(timeout);
- } catch (InterruptedException ex) {
- }
- if (!done[0]) {
- Log.w(TAG, "Timed out waiting for NFC, Radio and Bluetooth shutdown.");
- }
- }
-
- /**
- * Do not call this directly. Use {@link #reboot(Context, String, boolean)}
- * or {@link #shutdown(Context, boolean)} instead.
- *
- * @param reboot true to reboot or false to shutdown
- * @param reason reason for reboot
- */
- public static void rebootOrShutdown(boolean reboot, String reason) {
- if (reboot) {
- Log.i(TAG, "Rebooting, reason: " + reason);
- try {
- PowerManagerService.lowLevelReboot(reason);
- } catch (Exception e) {
- Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);
- }
- } else if (SHUTDOWN_VIBRATE_MS > 0) {
- // vibrate before shutting down
- Vibrator vibrator = new SystemVibrator();
- try {
- vibrator.vibrate(SHUTDOWN_VIBRATE_MS);
- } catch (Exception e) {
- // Failure to vibrate shouldn't interrupt shutdown. Just log it.
- Log.w(TAG, "Failed to vibrate during shutdown.", e);
- }
-
- // vibrator is asynchronous so we need to wait to avoid shutting down too soon.
- try {
- Thread.sleep(SHUTDOWN_VIBRATE_MS);
- } catch (InterruptedException unused) {
- }
- }
-
- // Shutdown power
- Log.i(TAG, "Performing low-level shutdown...");
- PowerManagerService.lowLevelShutdown();
- }
-}
diff --git a/services/java/com/android/server/pm/UserManager.java b/services/java/com/android/server/pm/UserManager.java
deleted file mode 100644
index 4e9e666..0000000
--- a/services/java/com/android/server/pm/UserManager.java
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.server.pm;
-
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastXmlSerializer;
-
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
-import android.os.Environment;
-import android.os.FileUtils;
-import android.os.SystemClock;
-import android.os.UserId;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.Xml;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-public class UserManager {
- private static final String TAG_NAME = "name";
-
- private static final String ATTR_FLAGS = "flags";
-
- private static final String ATTR_ID = "id";
-
- private static final String TAG_USERS = "users";
-
- private static final String TAG_USER = "user";
-
- private static final String LOG_TAG = "UserManager";
-
- private static final String USER_INFO_DIR = "system" + File.separator + "users";
- private static final String USER_LIST_FILENAME = "userlist.xml";
-
- private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
-
- private final File mUsersDir;
- private final File mUserListFile;
- private int[] mUserIds;
-
- private Installer mInstaller;
- private File mBaseUserPath;
-
- /**
- * Available for testing purposes.
- */
- UserManager(File dataDir, File baseUserPath) {
- mUsersDir = new File(dataDir, USER_INFO_DIR);
- mUsersDir.mkdirs();
- // Make zeroth user directory, for services to migrate their files to that location
- File userZeroDir = new File(mUsersDir, "0");
- userZeroDir.mkdirs();
- mBaseUserPath = baseUserPath;
- FileUtils.setPermissions(mUsersDir.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG
- |FileUtils.S_IROTH|FileUtils.S_IXOTH,
- -1, -1);
- mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
- readUserList();
- }
-
- public UserManager(Installer installer, File baseUserPath) {
- this(Environment.getDataDirectory(), baseUserPath);
- mInstaller = installer;
- }
-
- public List<UserInfo> getUsers() {
- synchronized (mUsers) {
- ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
- for (int i = 0; i < mUsers.size(); i++) {
- users.add(mUsers.valueAt(i));
- }
- return users;
- }
- }
-
- public UserInfo getUser(int userId) {
- synchronized (mUsers) {
- UserInfo info = mUsers.get(userId);
- return info;
- }
- }
-
- public boolean exists(int userId) {
- synchronized (mUsers) {
- return ArrayUtils.contains(mUserIds, userId);
- }
- }
-
- public void updateUserName(int userId, String name) {
- synchronized (mUsers) {
- UserInfo info = mUsers.get(userId);
- if (name != null && !name.equals(info.name)) {
- info.name = name;
- writeUserLocked(info);
- }
- }
- }
-
- /**
- * Returns an array of user ids. This array is cached here for quick access, so do not modify or
- * cache it elsewhere.
- * @return the array of user ids.
- */
- int[] getUserIds() {
- return mUserIds;
- }
-
- private void readUserList() {
- synchronized (mUsers) {
- readUserListLocked();
- }
- }
-
- private void readUserListLocked() {
- if (!mUserListFile.exists()) {
- fallbackToSingleUserLocked();
- return;
- }
- FileInputStream fis = null;
- try {
- fis = new FileInputStream(mUserListFile);
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(fis, null);
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- ;
- }
-
- if (type != XmlPullParser.START_TAG) {
- Slog.e(LOG_TAG, "Unable to read user list");
- fallbackToSingleUserLocked();
- return;
- }
-
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) {
- String id = parser.getAttributeValue(null, ATTR_ID);
- UserInfo user = readUser(Integer.parseInt(id));
- if (user != null) {
- mUsers.put(user.id, user);
- }
- }
- }
- updateUserIdsLocked();
- } catch (IOException ioe) {
- fallbackToSingleUserLocked();
- } catch (XmlPullParserException pe) {
- fallbackToSingleUserLocked();
- } finally {
- if (fis != null) {
- try {
- fis.close();
- } catch (IOException e) {
- }
- }
- }
- }
-
- private void fallbackToSingleUserLocked() {
- // Create the primary user
- UserInfo primary = new UserInfo(0, "Primary",
- UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
- mUsers.put(0, primary);
- updateUserIdsLocked();
-
- writeUserListLocked();
- writeUserLocked(primary);
- }
-
- /*
- * Writes the user file in this format:
- *
- * <user flags="20039023" id="0">
- * <name>Primary</name>
- * </user>
- */
- private void writeUserLocked(UserInfo userInfo) {
- FileOutputStream fos = null;
- try {
- final File mUserFile = new File(mUsersDir, userInfo.id + ".xml");
- fos = new FileOutputStream(mUserFile);
- final BufferedOutputStream bos = new BufferedOutputStream(fos);
-
- // XmlSerializer serializer = XmlUtils.serializerInstance();
- final XmlSerializer serializer = new FastXmlSerializer();
- serializer.setOutput(bos, "utf-8");
- serializer.startDocument(null, true);
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-
- serializer.startTag(null, TAG_USER);
- serializer.attribute(null, ATTR_ID, Integer.toString(userInfo.id));
- serializer.attribute(null, ATTR_FLAGS, Integer.toString(userInfo.flags));
-
- serializer.startTag(null, TAG_NAME);
- serializer.text(userInfo.name);
- serializer.endTag(null, TAG_NAME);
-
- serializer.endTag(null, TAG_USER);
-
- serializer.endDocument();
- } catch (IOException ioe) {
- Slog.e(LOG_TAG, "Error writing user info " + userInfo.id + "\n" + ioe);
- } finally {
- if (fos != null) {
- try {
- fos.close();
- } catch (IOException ioe) {
- }
- }
- }
- }
-
- /*
- * Writes the user list file in this format:
- *
- * <users>
- * <user id="0"></user>
- * <user id="2"></user>
- * </users>
- */
- private void writeUserListLocked() {
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(mUserListFile);
- final BufferedOutputStream bos = new BufferedOutputStream(fos);
-
- // XmlSerializer serializer = XmlUtils.serializerInstance();
- final XmlSerializer serializer = new FastXmlSerializer();
- serializer.setOutput(bos, "utf-8");
- serializer.startDocument(null, true);
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-
- serializer.startTag(null, TAG_USERS);
-
- for (int i = 0; i < mUsers.size(); i++) {
- UserInfo user = mUsers.valueAt(i);
- serializer.startTag(null, TAG_USER);
- serializer.attribute(null, ATTR_ID, Integer.toString(user.id));
- serializer.endTag(null, TAG_USER);
- }
-
- serializer.endTag(null, TAG_USERS);
-
- serializer.endDocument();
- } catch (IOException ioe) {
- Slog.e(LOG_TAG, "Error writing user list");
- } finally {
- if (fos != null) {
- try {
- fos.close();
- } catch (IOException ioe) {
- }
- }
- }
- }
-
- private UserInfo readUser(int id) {
- int flags = 0;
- String name = null;
-
- FileInputStream fis = null;
- try {
- File userFile = new File(mUsersDir, Integer.toString(id) + ".xml");
- fis = new FileInputStream(userFile);
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(fis, null);
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- ;
- }
-
- if (type != XmlPullParser.START_TAG) {
- Slog.e(LOG_TAG, "Unable to read user " + id);
- return null;
- }
-
- if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) {
- String storedId = parser.getAttributeValue(null, ATTR_ID);
- if (Integer.parseInt(storedId) != id) {
- Slog.e(LOG_TAG, "User id does not match the file name");
- return null;
- }
- String flagString = parser.getAttributeValue(null, ATTR_FLAGS);
- flags = Integer.parseInt(flagString);
-
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- }
- if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_NAME)) {
- type = parser.next();
- if (type == XmlPullParser.TEXT) {
- name = parser.getText();
- }
- }
- }
-
- UserInfo userInfo = new UserInfo(id, name, flags);
- return userInfo;
-
- } catch (IOException ioe) {
- } catch (XmlPullParserException pe) {
- } finally {
- if (fis != null) {
- try {
- fis.close();
- } catch (IOException e) {
- }
- }
- }
- return null;
- }
-
- public UserInfo createUser(String name, int flags) {
- int userId = getNextAvailableId();
- UserInfo userInfo = new UserInfo(userId, name, flags);
- File userPath = new File(mBaseUserPath, Integer.toString(userId));
- if (!createPackageFolders(userId, userPath)) {
- return null;
- }
- synchronized (mUsers) {
- mUsers.put(userId, userInfo);
- writeUserListLocked();
- writeUserLocked(userInfo);
- updateUserIdsLocked();
- }
- return userInfo;
- }
-
- /**
- * Removes a user and all data directories created for that user. This method should be called
- * after the user's processes have been terminated.
- * @param id the user's id
- */
- public boolean removeUser(int id) {
- synchronized (mUsers) {
- return removeUserLocked(id);
- }
- }
-
- private boolean removeUserLocked(int id) {
- // Remove from the list
- UserInfo userInfo = mUsers.get(id);
- if (userInfo != null) {
- // Remove this user from the list
- mUsers.remove(id);
- // Remove user file
- File userFile = new File(mUsersDir, id + ".xml");
- userFile.delete();
- // Update the user list
- writeUserListLocked();
- updateUserIdsLocked();
- return true;
- }
- return false;
- }
-
- public void installPackageForAllUsers(String packageName, int uid) {
- for (int userId : mUserIds) {
- // Don't do it for the primary user, it will become recursive.
- if (userId == 0)
- continue;
- mInstaller.createUserData(packageName, UserId.getUid(userId, uid),
- userId);
- }
- }
-
- public void clearUserDataForAllUsers(String packageName) {
- for (int userId : mUserIds) {
- // Don't do it for the primary user, it will become recursive.
- if (userId == 0)
- continue;
- mInstaller.clearUserData(packageName, userId);
- }
- }
-
- public void removePackageForAllUsers(String packageName) {
- for (int userId : mUserIds) {
- // Don't do it for the primary user, it will become recursive.
- if (userId == 0)
- continue;
- mInstaller.remove(packageName, userId);
- }
- }
-
- /**
- * 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()];
- }
- for (int i = 0; i < mUsers.size(); i++) {
- mUserIds[i] = mUsers.keyAt(i);
- }
- }
-
- /**
- * Returns the next available user id, filling in any holes in the ids.
- * TODO: May not be a good idea to recycle ids, in case it results in confusion
- * for data and battery stats collection, or unexpected cross-talk.
- * @return
- */
- private int getNextAvailableId() {
- int i = 0;
- while (i < Integer.MAX_VALUE) {
- if (mUsers.indexOfKey(i) < 0) {
- break;
- }
- i++;
- }
- return i;
- }
-
- private boolean createPackageFolders(int id, File userPath) {
- // mInstaller may not be available for unit-tests.
- if (mInstaller == null) return true;
-
- // Create the user path
- userPath.mkdir();
- FileUtils.setPermissions(userPath.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
- | FileUtils.S_IXOTH, -1, -1);
-
- mInstaller.cloneUserData(0, id, false);
-
- return true;
- }
-
- boolean removePackageFolders(int id) {
- // mInstaller may not be available for unit-tests.
- if (mInstaller == null) return true;
-
- mInstaller.removeUserDataDirs(id);
- return true;
- }
-}
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
new file mode 100644
index 0000000..be86628
--- /dev/null
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -0,0 +1,723 @@
+/*
+ * Copyright (C) 2011 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 com.android.server.pm;
+
+import static android.os.ParcelFileDescriptor.MODE_CREATE;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastXmlSerializer;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.IStopUserCallback;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.IUserManager;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.Xml;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+public class UserManagerService extends IUserManager.Stub {
+
+ private static final String LOG_TAG = "UserManagerService";
+
+ private static final String TAG_NAME = "name";
+ private static final String ATTR_FLAGS = "flags";
+ private static final String ATTR_ICON_PATH = "icon";
+ private static final String ATTR_ID = "id";
+ private static final String ATTR_SERIAL_NO = "serialNumber";
+ private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
+ private static final String TAG_USERS = "users";
+ private static final String TAG_USER = "user";
+
+ private static final String USER_INFO_DIR = "system" + File.separator + "users";
+ private static final String USER_LIST_FILENAME = "userlist.xml";
+ private static final String USER_PHOTO_FILENAME = "photo.png";
+
+ private final Context mContext;
+ private final PackageManagerService mPm;
+ private final Object mInstallLock;
+ private final Object mPackagesLock;
+
+ private final File mUsersDir;
+ private final File mUserListFile;
+ private final File mBaseUserPath;
+
+ private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
+
+ private final int mUserLimit;
+
+ private int[] mUserIds;
+ private boolean mGuestEnabled;
+ private int mNextSerialNumber;
+
+ private static UserManagerService sInstance;
+
+ public static UserManagerService getInstance() {
+ synchronized (UserManagerService.class) {
+ return sInstance;
+ }
+ }
+
+ /**
+ * Available for testing purposes.
+ */
+ UserManagerService(File dataDir, File baseUserPath) {
+ this(null, null, new Object(), new Object(), dataDir, baseUserPath);
+ }
+
+ /**
+ * Called by package manager to create the service. This is closely
+ * associated with the package manager, and the given lock is the
+ * package manager's own lock.
+ */
+ UserManagerService(Context context, PackageManagerService pm,
+ Object installLock, Object packagesLock) {
+ this(context, pm, installLock, packagesLock,
+ Environment.getDataDirectory(),
+ new File(Environment.getDataDirectory(), "user"));
+ }
+
+ /**
+ * Available for testing purposes.
+ */
+ private UserManagerService(Context context, PackageManagerService pm,
+ Object installLock, Object packagesLock,
+ File dataDir, File baseUserPath) {
+ synchronized (UserManagerService.class) {
+ mContext = context;
+ mPm = pm;
+ mInstallLock = installLock;
+ mPackagesLock = packagesLock;
+ mUserLimit = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_multiuserMaximumUsers);
+ mUsersDir = new File(dataDir, USER_INFO_DIR);
+ mUsersDir.mkdirs();
+ // Make zeroth user directory, for services to migrate their files to that location
+ File userZeroDir = new File(mUsersDir, "0");
+ userZeroDir.mkdirs();
+ mBaseUserPath = baseUserPath;
+ FileUtils.setPermissions(mUsersDir.toString(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG
+ |FileUtils.S_IROTH|FileUtils.S_IXOTH,
+ -1, -1);
+ mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
+ readUserList();
+ sInstance = this;
+ }
+ }
+
+ @Override
+ public List<UserInfo> getUsers() {
+ checkManageUsersPermission("query users");
+ synchronized (mPackagesLock) {
+ ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
+ for (int i = 0; i < mUsers.size(); i++) {
+ users.add(mUsers.valueAt(i));
+ }
+ return users;
+ }
+ }
+
+ @Override
+ public UserInfo getUserInfo(int userId) {
+ checkManageUsersPermission("query user");
+ synchronized (mPackagesLock) {
+ return getUserInfoLocked(userId);
+ }
+ }
+
+ /*
+ * Should be locked on mUsers before calling this.
+ */
+ private UserInfo getUserInfoLocked(int userId) {
+ return mUsers.get(userId);
+ }
+
+ public boolean exists(int userId) {
+ synchronized (mPackagesLock) {
+ return ArrayUtils.contains(mUserIds, userId);
+ }
+ }
+
+ @Override
+ public void setUserName(int userId, String name) {
+ checkManageUsersPermission("rename users");
+ synchronized (mPackagesLock) {
+ UserInfo info = mUsers.get(userId);
+ if (name != null && !name.equals(info.name)) {
+ info.name = name;
+ writeUserLocked(info);
+ }
+ }
+ sendUserInfoChangedBroadcast(userId);
+ }
+
+ @Override
+ public void setUserIcon(int userId, Bitmap bitmap) {
+ checkManageUsersPermission("update users");
+ synchronized (mPackagesLock) {
+ UserInfo info = mUsers.get(userId);
+ if (info == null) return;
+ writeBitmapLocked(info, bitmap);
+ writeUserLocked(info);
+ }
+ sendUserInfoChangedBroadcast(userId);
+ }
+
+ private void sendUserInfoChangedBroadcast(int userId) {
+ Intent changedIntent = new Intent(Intent.ACTION_USER_INFO_CHANGED);
+ changedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ changedIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(changedIntent, new UserHandle(userId));
+ }
+
+ @Override
+ public Bitmap getUserIcon(int userId) {
+ checkManageUsersPermission("read users");
+ synchronized (mPackagesLock) {
+ UserInfo info = mUsers.get(userId);
+ if (info == null || info.iconPath == null) return null;
+ return BitmapFactory.decodeFile(info.iconPath);
+ }
+ }
+
+ @Override
+ public void setGuestEnabled(boolean enable) {
+ checkManageUsersPermission("enable guest users");
+ synchronized (mPackagesLock) {
+ if (mGuestEnabled != enable) {
+ mGuestEnabled = enable;
+ // Erase any guest user that currently exists
+ for (int i = 0; i < mUsers.size(); i++) {
+ UserInfo user = mUsers.valueAt(i);
+ if (user.isGuest()) {
+ if (!enable) {
+ removeUser(user.id);
+ }
+ return;
+ }
+ }
+ // No guest was found
+ if (enable) {
+ createUser("Guest", UserInfo.FLAG_GUEST);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean isGuestEnabled() {
+ synchronized (mPackagesLock) {
+ return mGuestEnabled;
+ }
+ }
+
+ @Override
+ public void wipeUser(int userHandle) {
+ checkManageUsersPermission("wipe user");
+ // TODO:
+ }
+
+ public void makeInitialized(int userId) {
+ checkManageUsersPermission("makeInitialized");
+ synchronized (mPackagesLock) {
+ UserInfo info = mUsers.get(userId);
+ if (info != null && (info.flags&UserInfo.FLAG_INITIALIZED) == 0) {
+ info.flags |= UserInfo.FLAG_INITIALIZED;
+ writeUserLocked(info);
+ }
+ }
+ }
+
+ /**
+ * Check if we've hit the limit of how many users can be created.
+ */
+ private boolean isUserLimitReachedLocked() {
+ int nUsers = mUsers.size();
+ return nUsers >= mUserLimit;
+ }
+
+ /**
+ * Enforces that only the system UID or root's UID or apps that have the
+ * {@link android.Manifest.permission.MANAGE_USERS MANAGE_USERS}
+ * permission can make certain calls to the UserManager.
+ *
+ * @param message used as message if SecurityException is thrown
+ * @throws SecurityException if the caller is not system or root
+ */
+ private static final void checkManageUsersPermission(String message) {
+ final int uid = Binder.getCallingUid();
+ if (uid != Process.SYSTEM_UID && uid != 0
+ && ActivityManager.checkComponentPermission(
+ android.Manifest.permission.MANAGE_USERS,
+ uid, -1, true) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("You need MANAGE_USERS permission to: " + message);
+ }
+ }
+
+ private void writeBitmapLocked(UserInfo info, Bitmap bitmap) {
+ try {
+ File dir = new File(mUsersDir, Integer.toString(info.id));
+ File file = new File(dir, USER_PHOTO_FILENAME);
+ if (!dir.exists()) {
+ dir.mkdir();
+ FileUtils.setPermissions(
+ dir.getPath(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+ -1, -1);
+ }
+ FileOutputStream os;
+ if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, os = new FileOutputStream(file))) {
+ info.iconPath = file.getAbsolutePath();
+ }
+ try {
+ os.close();
+ } catch (IOException ioe) {
+ // What the ... !
+ }
+ } catch (FileNotFoundException e) {
+ Slog.w(LOG_TAG, "Error setting photo for user ", e);
+ }
+ }
+
+ /**
+ * Returns an array of user ids. This array is cached here for quick access, so do not modify or
+ * cache it elsewhere.
+ * @return the array of user ids.
+ */
+ public int[] getUserIds() {
+ synchronized (mPackagesLock) {
+ return mUserIds;
+ }
+ }
+
+ int[] getUserIdsLPr() {
+ return mUserIds;
+ }
+
+ private void readUserList() {
+ synchronized (mPackagesLock) {
+ readUserListLocked();
+ }
+ }
+
+ private void readUserListLocked() {
+ mGuestEnabled = false;
+ if (!mUserListFile.exists()) {
+ fallbackToSingleUserLocked();
+ return;
+ }
+ FileInputStream fis = null;
+ AtomicFile userListFile = new AtomicFile(mUserListFile);
+ try {
+ fis = userListFile.openRead();
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(fis, null);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ Slog.e(LOG_TAG, "Unable to read user list");
+ fallbackToSingleUserLocked();
+ return;
+ }
+
+ mNextSerialNumber = -1;
+ if (parser.getName().equals(TAG_USERS)) {
+ String lastSerialNumber = parser.getAttributeValue(null, ATTR_NEXT_SERIAL_NO);
+ if (lastSerialNumber != null) {
+ mNextSerialNumber = Integer.parseInt(lastSerialNumber);
+ }
+ }
+
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) {
+ String id = parser.getAttributeValue(null, ATTR_ID);
+ UserInfo user = readUser(Integer.parseInt(id));
+ if (user != null) {
+ mUsers.put(user.id, user);
+ if (user.isGuest()) {
+ mGuestEnabled = true;
+ }
+ if (mNextSerialNumber < 0 || mNextSerialNumber <= user.id) {
+ mNextSerialNumber = user.id + 1;
+ }
+ }
+ }
+ }
+ updateUserIdsLocked();
+ } catch (IOException ioe) {
+ fallbackToSingleUserLocked();
+ } catch (XmlPullParserException pe) {
+ fallbackToSingleUserLocked();
+ } finally {
+ if (fis != null) {
+ try {
+ fis.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ private void fallbackToSingleUserLocked() {
+ // Create the primary user
+ UserInfo primary = new UserInfo(0, "Primary", null,
+ UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
+ mUsers.put(0, primary);
+ updateUserIdsLocked();
+
+ writeUserListLocked();
+ writeUserLocked(primary);
+ }
+
+ /*
+ * Writes the user file in this format:
+ *
+ * <user flags="20039023" id="0">
+ * <name>Primary</name>
+ * </user>
+ */
+ private void writeUserLocked(UserInfo userInfo) {
+ FileOutputStream fos = null;
+ AtomicFile userFile = new AtomicFile(new File(mUsersDir, userInfo.id + ".xml"));
+ try {
+ fos = userFile.startWrite();
+ final BufferedOutputStream bos = new BufferedOutputStream(fos);
+
+ // XmlSerializer serializer = XmlUtils.serializerInstance();
+ final XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(bos, "utf-8");
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ serializer.startTag(null, TAG_USER);
+ serializer.attribute(null, ATTR_ID, Integer.toString(userInfo.id));
+ serializer.attribute(null, ATTR_SERIAL_NO, Integer.toString(userInfo.serialNumber));
+ serializer.attribute(null, ATTR_FLAGS, Integer.toString(userInfo.flags));
+ if (userInfo.iconPath != null) {
+ serializer.attribute(null, ATTR_ICON_PATH, userInfo.iconPath);
+ }
+
+ serializer.startTag(null, TAG_NAME);
+ serializer.text(userInfo.name);
+ serializer.endTag(null, TAG_NAME);
+
+ serializer.endTag(null, TAG_USER);
+
+ serializer.endDocument();
+ userFile.finishWrite(fos);
+ } catch (Exception ioe) {
+ Slog.e(LOG_TAG, "Error writing user info " + userInfo.id + "\n" + ioe);
+ userFile.failWrite(fos);
+ }
+ }
+
+ /*
+ * Writes the user list file in this format:
+ *
+ * <users nextSerialNumber="3">
+ * <user id="0"></user>
+ * <user id="2"></user>
+ * </users>
+ */
+ private void writeUserListLocked() {
+ FileOutputStream fos = null;
+ AtomicFile userListFile = new AtomicFile(mUserListFile);
+ try {
+ fos = userListFile.startWrite();
+ final BufferedOutputStream bos = new BufferedOutputStream(fos);
+
+ // XmlSerializer serializer = XmlUtils.serializerInstance();
+ final XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(bos, "utf-8");
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ serializer.startTag(null, TAG_USERS);
+ serializer.attribute(null, ATTR_NEXT_SERIAL_NO, Integer.toString(mNextSerialNumber));
+
+ for (int i = 0; i < mUsers.size(); i++) {
+ UserInfo user = mUsers.valueAt(i);
+ serializer.startTag(null, TAG_USER);
+ serializer.attribute(null, ATTR_ID, Integer.toString(user.id));
+ serializer.endTag(null, TAG_USER);
+ }
+
+ serializer.endTag(null, TAG_USERS);
+
+ serializer.endDocument();
+ userListFile.finishWrite(fos);
+ } catch (Exception e) {
+ userListFile.failWrite(fos);
+ Slog.e(LOG_TAG, "Error writing user list");
+ }
+ }
+
+ private UserInfo readUser(int id) {
+ int flags = 0;
+ int serialNumber = id;
+ String name = null;
+ String iconPath = null;
+
+ FileInputStream fis = null;
+ try {
+ AtomicFile userFile =
+ new AtomicFile(new File(mUsersDir, Integer.toString(id) + ".xml"));
+ fis = userFile.openRead();
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(fis, null);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ Slog.e(LOG_TAG, "Unable to read user " + id);
+ return null;
+ }
+
+ if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) {
+ String storedId = parser.getAttributeValue(null, ATTR_ID);
+ if (Integer.parseInt(storedId) != id) {
+ Slog.e(LOG_TAG, "User id does not match the file name");
+ return null;
+ }
+ String serialNumberValue = parser.getAttributeValue(null, ATTR_SERIAL_NO);
+ if (serialNumberValue != null) {
+ serialNumber = Integer.parseInt(serialNumberValue);
+ }
+ String flagString = parser.getAttributeValue(null, ATTR_FLAGS);
+ flags = Integer.parseInt(flagString);
+ iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH);
+
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ }
+ if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_NAME)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ name = parser.getText();
+ }
+ }
+ }
+
+ UserInfo userInfo = new UserInfo(id, name, iconPath, flags);
+ userInfo.serialNumber = serialNumber;
+ return userInfo;
+
+ } catch (IOException ioe) {
+ } catch (XmlPullParserException pe) {
+ } finally {
+ if (fis != null) {
+ try {
+ fis.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public UserInfo createUser(String name, int flags) {
+ checkManageUsersPermission("Only the system can create users");
+
+ final long ident = Binder.clearCallingIdentity();
+ final UserInfo userInfo;
+ try {
+ synchronized (mInstallLock) {
+ synchronized (mPackagesLock) {
+ if (isUserLimitReachedLocked()) return null;
+ int userId = getNextAvailableIdLocked();
+ userInfo = new UserInfo(userId, name, null, flags);
+ File userPath = new File(mBaseUserPath, Integer.toString(userId));
+ userInfo.serialNumber = mNextSerialNumber++;
+ mUsers.put(userId, userInfo);
+ writeUserListLocked();
+ writeUserLocked(userInfo);
+ updateUserIdsLocked();
+ mPm.createNewUserLILPw(userId, userPath);
+ }
+ }
+ if (userInfo != null) {
+ Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
+ addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);
+ mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
+ android.Manifest.permission.MANAGE_USERS);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return userInfo;
+ }
+
+ /**
+ * Removes a user and all data directories created for that user. This method should be called
+ * after the user's processes have been terminated.
+ * @param id the user's id
+ */
+ public boolean removeUser(int userHandle) {
+ checkManageUsersPermission("Only the system can remove users");
+ final UserInfo user;
+ synchronized (mPackagesLock) {
+ user = mUsers.get(userHandle);
+ if (userHandle == 0 || user == null) {
+ return false;
+ }
+ }
+
+ int res;
+ try {
+ res = ActivityManagerNative.getDefault().stopUser(userHandle,
+ new IStopUserCallback.Stub() {
+ @Override
+ public void userStopped(int userId) {
+ finishRemoveUser(userId);
+ }
+ @Override
+ public void userStopAborted(int userId) {
+ }
+ });
+ } catch (RemoteException e) {
+ return false;
+ }
+
+ return res == ActivityManager.USER_OP_SUCCESS;
+ }
+
+ void finishRemoveUser(int userHandle) {
+ synchronized (mInstallLock) {
+ synchronized (mPackagesLock) {
+ // Cleanup package manager settings
+ mPm.cleanUpUserLILPw(userHandle);
+
+ // Remove this user from the list
+ mUsers.remove(userHandle);
+ // Remove user file
+ AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
+ userFile.delete();
+ // Update the user list
+ writeUserListLocked();
+ updateUserIdsLocked();
+ removeDirectoryRecursive(Environment.getUserSystemDirectory(userHandle));
+ }
+ }
+
+ // Let other services shutdown any activity
+ long ident = Binder.clearCallingIdentity();
+ try {
+ Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
+ addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
+ mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
+ android.Manifest.permission.MANAGE_USERS);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private void removeDirectoryRecursive(File parent) {
+ if (parent.isDirectory()) {
+ String[] files = parent.list();
+ for (String filename : files) {
+ File child = new File(parent, filename);
+ removeDirectoryRecursive(child);
+ }
+ }
+ parent.delete();
+ }
+
+ @Override
+ public int getUserSerialNumber(int userHandle) {
+ synchronized (mPackagesLock) {
+ if (!exists(userHandle)) return -1;
+ return getUserInfoLocked(userHandle).serialNumber;
+ }
+ }
+
+ @Override
+ public int getUserHandle(int userSerialNumber) {
+ synchronized (mPackagesLock) {
+ for (int userId : mUserIds) {
+ if (getUserInfoLocked(userId).serialNumber == userSerialNumber) return userId;
+ }
+ // Not found
+ return -1;
+ }
+ }
+
+ /**
+ * Caches the list of user ids in an array, adjusting the array size when necessary.
+ */
+ private void updateUserIdsLocked() {
+ int[] newUsers = new int[mUsers.size()];
+ for (int i = 0; i < mUsers.size(); i++) {
+ newUsers[i] = mUsers.keyAt(i);
+ }
+ mUserIds = newUsers;
+ }
+
+ /**
+ * Returns the next available user id, filling in any holes in the ids.
+ * TODO: May not be a good idea to recycle ids, in case it results in confusion
+ * for data and battery stats collection, or unexpected cross-talk.
+ * @return
+ */
+ private int getNextAvailableIdLocked() {
+ synchronized (mPackagesLock) {
+ int i = 10;
+ while (i < Integer.MAX_VALUE) {
+ if (mUsers.indexOfKey(i) < 0) {
+ break;
+ }
+ i++;
+ }
+ return i;
+ }
+ }
+}