Merge "Bind to the correct default container service when installing/moving/measuring pkgs" into jb-mr1-dev
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 0bc0f91..7642670 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -331,12 +331,16 @@
notifyListener(v1, true /* removed */);
}
if (changes.length() > 0) {
- Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
- serviceInfos.size() + " services:\n" + changes);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
+ serviceInfos.size() + " services:\n" + changes);
+ }
writePersistentServicesLocked();
} else {
- Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
- serviceInfos.size() + " services unchanged");
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
+ serviceInfos.size() + " services unchanged");
+ }
}
mPersistentServicesFileDidNotExist = false;
}
diff --git a/core/java/android/service/dreams/DreamManagerService.java b/core/java/android/service/dreams/DreamManagerService.java
index 4b0f7c5..2cec6c3 100644
--- a/core/java/android/service/dreams/DreamManagerService.java
+++ b/core/java/android/service/dreams/DreamManagerService.java
@@ -105,7 +105,7 @@
public ComponentName[] getDreamComponents() {
// TODO(dsandler) don't load this every time, watch the value
String names = Settings.Secure.getString(mContext.getContentResolver(), SCREENSAVER_COMPONENTS);
- return componentsFromString(names);
+ return names == null ? null : componentsFromString(names);
}
// IDreamManager method
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index ac3dee4..9051285 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -357,11 +357,6 @@
// From the Unicode Line Breaking Algorithm (at least approximately)
boolean isLineBreak = isSpaceOrTab ||
- // .,:; are class IS breakpoints, except when adjacent to digits
- ((c == CHAR_DOT || c == CHAR_COMMA ||
- c == CHAR_COLON || c == CHAR_SEMICOLON) &&
- (j - 1 < here || !Character.isDigit(chs[j - 1 - paraStart])) &&
- (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) ||
// / is class SY and - is class HY, except when followed by a digit
((c == CHAR_SLASH || c == CHAR_HYPHEN) &&
(j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) ||
@@ -959,10 +954,6 @@
private static final char CHAR_NEW_LINE = '\n';
private static final char CHAR_TAB = '\t';
private static final char CHAR_SPACE = ' ';
- private static final char CHAR_DOT = '.';
- private static final char CHAR_COMMA = ',';
- private static final char CHAR_COLON = ':';
- private static final char CHAR_SEMICOLON = ';';
private static final char CHAR_SLASH = '/';
private static final char CHAR_HYPHEN = '-';
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 61c942d..423135f 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -973,6 +973,12 @@
// Start selection mode if needed. We don't need to if we're unchecking something.
if (value && mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) {
+ if (mMultiChoiceModeCallback == null ||
+ !mMultiChoiceModeCallback.hasWrappedCallback()) {
+ throw new IllegalStateException("AbsListView: attempted to start selection mode " +
+ "for CHOICE_MODE_MULTIPLE_MODAL but no choice mode callback was " +
+ "supplied. Call setMultiChoiceModeListener to set a callback.");
+ }
mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
}
@@ -5945,6 +5951,10 @@
mWrapped = wrapped;
}
+ public boolean hasWrappedCallback() {
+ return mWrapped != null;
+ }
+
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
if (mWrapped.onCreateActionMode(mode, menu)) {
// Initialize checked graphic state?
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index f91201a..bc78adc 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -175,11 +175,7 @@
@Override
protected void internalSetPadding(int left, int top, int right, int bottom) {
super.internalSetPadding(left, top, right, bottom);
- if (isLayoutRtl()) {
- mBasePadding = mUserPaddingLeft;
- } else {
- mBasePadding = mUserPaddingRight;
- }
+ setBasePadding(isLayoutRtl());
}
@Override
@@ -201,13 +197,21 @@
@Override
public void setPadding(int left, int top, int right, int bottom) {
super.setPadding(left, top, right, bottom);
- mBasePadding = getPaddingEnd();
+ setBasePadding(isLayoutRtl());
}
@Override
public void setPaddingRelative(int start, int top, int end, int bottom) {
super.setPaddingRelative(start, top, end, bottom);
- mBasePadding = getPaddingEnd();
+ setBasePadding(isLayoutRtl());
+ }
+
+ private void setBasePadding(boolean isLayoutRtl) {
+ if (isLayoutRtl) {
+ mBasePadding = mPaddingLeft;
+ } else {
+ mBasePadding = mPaddingRight;
+ }
}
@Override
@@ -237,11 +241,11 @@
final int left;
final int right;
if (isLayoutRtl) {
- right = getPaddingEnd();
- left = right - mCheckMarkWidth;
- } else {
- left = width - getPaddingEnd();
+ left = mBasePadding;
right = left + mCheckMarkWidth;
+ } else {
+ right = width - mBasePadding;
+ left = right - mCheckMarkWidth;
}
checkMarkDrawable.setBounds( left, top, right, bottom);
checkMarkDrawable.draw(canvas);
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index 08d9f49..b620568 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -23,7 +23,9 @@
import android.app.ActionBar;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.view.Gravity;
import android.view.View;
@@ -38,6 +40,7 @@
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
+import android.widget.Toast;
/**
* This widget implements the dynamic action bar tab behavior that can change
@@ -352,7 +355,7 @@
tabView.getTab().select();
}
- private class TabView extends LinearLayout {
+ private class TabView extends LinearLayout implements OnLongClickListener {
private ActionBar.Tab mTab;
private TextView mTextView;
private ImageView mIconView;
@@ -426,7 +429,8 @@
mIconView.setImageDrawable(null);
}
- if (text != null) {
+ final boolean hasText = !TextUtils.isEmpty(text);
+ if (hasText) {
if (mTextView == null) {
TextView textView = new TextView(getContext(), null,
com.android.internal.R.attr.actionBarTabTextStyle);
@@ -448,9 +452,35 @@
if (mIconView != null) {
mIconView.setContentDescription(tab.getContentDescription());
}
+
+ if (!hasText && !TextUtils.isEmpty(tab.getContentDescription())) {
+ setOnLongClickListener(this);
+ } else {
+ setOnLongClickListener(null);
+ setLongClickable(false);
+ }
}
}
+ public boolean onLongClick(View v) {
+ final int[] screenPos = new int[2];
+ getLocationOnScreen(screenPos);
+
+ final Context context = getContext();
+ final int width = getWidth();
+ final int height = getHeight();
+ final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
+
+ Toast cheatSheet = Toast.makeText(context, mTab.getContentDescription(),
+ Toast.LENGTH_SHORT);
+ // Show under the tab
+ cheatSheet.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL,
+ (screenPos[0] + width / 2) - screenWidth / 2, height);
+
+ cheatSheet.show();
+ return true;
+ }
+
public ActionBar.Tab getTab() {
return mTab;
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a6af144..7097891 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -197,7 +197,7 @@
Slog.i(TAG, "User Service");
ServiceManager.addService(Context.USER_SERVICE,
- UserManagerService.getInstance(context));
+ UserManagerService.getInstance());
mContentResolver = context.getContentResolver();
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index daef773..0345df1 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -961,8 +961,8 @@
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
- sUserManager = UserManagerService.getInstance(context);
- sUserManager.setInstaller(this, mInstaller);
+ sUserManager = new UserManagerService(context, this,
+ mInstallLock, mPackages);
readPermissions();
@@ -1156,8 +1156,7 @@
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()) {
@@ -1206,9 +1205,7 @@
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 "
@@ -1343,13 +1340,7 @@
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);
@@ -1829,9 +1820,11 @@
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 {
@@ -1852,9 +1845,11 @@
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 {
@@ -3005,7 +3000,9 @@
}
ProviderInfo info = PackageParser.generateProviderInfo(p, flags,
ps.readUserState(userId), userId);
- finalList.add(info);
+ if (info != null) {
+ finalList.add(info);
+ }
}
}
}
@@ -3038,8 +3035,11 @@
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);
+ }
}
}
}
@@ -3200,7 +3200,7 @@
InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString);
- synchronized (mInstaller) {
+ synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
synchronized (mPackages) {
@@ -3256,7 +3256,7 @@
+ " better than installed " + ps.versionCode);
InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString);
- synchronized (mInstaller) {
+ synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
}
@@ -3490,6 +3490,36 @@
}
}
+ 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;
+ }
+ }
+ return res;
+ }
+
private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, long currentTime, UserHandle user) {
File scanFile = new File(pkg.mScanPath);
@@ -3842,11 +3872,9 @@
|| (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 ";
@@ -3858,8 +3886,7 @@
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
@@ -3868,9 +3895,6 @@
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
}
- // Create data directories for all users
- sUserManager.installPackageForAllUsers(pkgName,
- pkg.applicationInfo.uid);
}
if (!recovered) {
mHasSystemUidErrors = true;
@@ -3908,15 +3932,12 @@
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();
@@ -5089,6 +5110,9 @@
}
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) {
@@ -7838,15 +7862,7 @@
}
}
if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
- int retCode = mInstaller.remove(packageName, 0);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove app data or cache directory for package: "
- + 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);
- }
+ removeDataDirsLI(packageName);
schedulePackageCleaning(packageName, UserHandle.USER_ALL, true);
}
// writer
@@ -9765,15 +9781,36 @@
}
/** Called by UserManagerService */
- void cleanUpUser(int userHandle) {
+ void cleanUpUserLILPw(int userHandle) {
// 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(userHandle);
+ Set<Entry<String, PackageSetting>> entries = mSettings.mPackages.entrySet();
+ for (Entry<String, PackageSetting> entry : entries) {
+ entry.getValue().removeUser(userHandle);
+ }
+ 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);
+ }
+ }
+
+ /** 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(userHandle));
- mSettings.removeUserLPr(userHandle);
+ mSettings.writePackageRestrictionsLPr(userHandle);
}
}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index a341304..68b594a 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -2476,7 +2476,7 @@
private List<UserInfo> getAllUsers() {
long id = Binder.clearCallingIdentity();
try {
- return UserManagerService.getInstance(mContext).getUsers();
+ return UserManagerService.getInstance().getUsers();
} catch (NullPointerException npe) {
// packagemanager not yet initialized
} finally {
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index 8899ea2..750aa72 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -25,7 +25,6 @@
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.Binder;
@@ -34,10 +33,8 @@
import android.os.IUserManager;
import android.os.ParcelFileDescriptor;
import android.os.Process;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.util.AtomicFile;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
@@ -72,59 +69,79 @@
private static final String USER_LIST_FILENAME = "userlist.xml";
private static final String USER_PHOTO_FILENAME = "photo.png";
- private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
+ 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 int[] mUserIds;
private boolean mGuestEnabled;
private int mNextSerialNumber;
- private Installer mInstaller;
- private File mBaseUserPath;
- private Context mContext;
private static UserManagerService sInstance;
- private PackageManagerService mPm;
- public synchronized static UserManagerService getInstance(Context context) {
- if (sInstance == null) {
- sInstance = new UserManagerService(context);
+ public static UserManagerService getInstance() {
+ synchronized (UserManagerService.class) {
+ return sInstance;
}
- return sInstance;
}
/**
* Available for testing purposes.
*/
UserManagerService(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();
+ this(null, null, new Object(), new Object(), dataDir, baseUserPath);
}
- public UserManagerService(Context context) {
- this(Environment.getDataDirectory(), new File(Environment.getDataDirectory(), "user"));
- mContext = context;
+ /**
+ * 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"));
}
- void setInstaller(PackageManagerService pm, Installer installer) {
- mInstaller = installer;
- mPm = pm;
+ /**
+ * 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;
+ 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 (mUsers) {
+ synchronized (mPackagesLock) {
ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
for (int i = 0; i < mUsers.size(); i++) {
users.add(mUsers.valueAt(i));
@@ -136,7 +153,7 @@
@Override
public UserInfo getUserInfo(int userId) {
checkManageUsersPermission("query user");
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
return getUserInfoLocked(userId);
}
}
@@ -149,7 +166,7 @@
}
public boolean exists(int userId) {
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
return ArrayUtils.contains(mUserIds, userId);
}
}
@@ -157,7 +174,7 @@
@Override
public void setUserName(int userId, String name) {
checkManageUsersPermission("rename users");
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
UserInfo info = mUsers.get(userId);
if (name != null && !name.equals(info.name)) {
info.name = name;
@@ -169,7 +186,7 @@
@Override
public ParcelFileDescriptor setUserIcon(int userId) {
checkManageUsersPermission("update users");
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
UserInfo info = mUsers.get(userId);
if (info == null) return null;
ParcelFileDescriptor fd = updateIconBitmapLocked(info);
@@ -183,7 +200,7 @@
@Override
public void setGuestEnabled(boolean enable) {
checkManageUsersPermission("enable guest users");
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
if (mGuestEnabled != enable) {
mGuestEnabled = enable;
// Erase any guest user that currently exists
@@ -206,7 +223,7 @@
@Override
public boolean isGuestEnabled() {
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
return mGuestEnabled;
}
}
@@ -262,13 +279,17 @@
* @return the array of user ids.
*/
int[] getUserIds() {
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
return mUserIds;
}
}
+ int[] getUserIdsLPr() {
+ return mUserIds;
+ }
+
private void readUserList() {
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
readUserListLocked();
}
}
@@ -501,15 +522,15 @@
int userId = getNextAvailableId();
UserInfo userInfo = new UserInfo(userId, name, null, flags);
File userPath = new File(mBaseUserPath, Integer.toString(userId));
- if (!createPackageFolders(userId, userPath)) {
- return null;
- }
- synchronized (mUsers) {
- userInfo.serialNumber = mNextSerialNumber++;
- mUsers.put(userId, userInfo);
- writeUserListLocked();
- writeUserLocked(userInfo);
- updateUserIdsLocked();
+ synchronized (mInstallLock) {
+ synchronized (mPackagesLock) {
+ 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);
@@ -528,24 +549,37 @@
*/
public boolean removeUser(int userHandle) {
checkManageUsersPermission("Only the system can remove users");
- boolean result;
- synchronized (mUsers) {
- result = removeUserLocked(userHandle);
- }
+ synchronized (mInstallLock) {
+ synchronized (mPackagesLock) {
+ final UserInfo user = mUsers.get(userHandle);
+ if (userHandle == 0 || user == null) {
+ return false;
+ }
- // Cleanup package manager settings
- mPm.cleanUpUser(userHandle);
+ // 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();
+ }
+ }
// Let other services shutdown any activity
Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_USERS);
- return result;
+ return true;
}
@Override
public int getUserSerialNumber(int userHandle) {
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
if (!exists(userHandle)) return -1;
return getUserInfoLocked(userHandle).serialNumber;
}
@@ -553,7 +587,7 @@
@Override
public int getUserHandle(int userSerialNumber) {
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
for (int userId : mUserIds) {
if (getUserInfoLocked(userId).serialNumber == userSerialNumber) return userId;
}
@@ -562,53 +596,6 @@
}
}
- private boolean removeUserLocked(int userHandle) {
- final UserInfo user = mUsers.get(userHandle);
- if (userHandle == 0 || user == null) {
- return false;
- }
-
- // 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();
-
- removePackageFolders(userHandle);
- return true;
- }
-
- 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, UserHandle.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.
*/
@@ -627,7 +614,7 @@
* @return
*/
private int getNextAvailableId() {
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
int i = 0;
while (i < Integer.MAX_VALUE) {
if (mUsers.indexOfKey(i) < 0) {
@@ -638,26 +625,4 @@
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;
- }
}