Package manager optimizations.

Addresses:
Issue #2550648: PackageManagerService setComponentEnabledSetting unconditionally
writes Settings xml
Issue #2549084: Make PackageManager.addPermission have async version

Also make the writing of settings when changing the preferred activities to use
the same async mechanism, and fiddle with thread priorities in the background
thread to go up to foreground priority when holding the lock to write settings
and a few other places.  (At some point we should really clean this up to never
acquire the main lock while in the background.)

Change-Id: Ib2b7632543f6fb3f92a225518579f3b2d15e1413
This commit is contained in:
Dianne Hackborn
2010-03-30 10:42:20 -07:00
parent 22375e4a73
commit d7c096845d
6 changed files with 189 additions and 38 deletions

View File

@@ -338,6 +338,9 @@ class PackageManagerService extends IPackageManager.Stub {
static final int MCS_RECONNECT = 10;
static final int MCS_GIVE_UP = 11;
static final int UPDATED_MEDIA_STATUS = 12;
static final int WRITE_SETTINGS = 13;
static final int WRITE_SETTINGS_DELAY = 10*1000; // 10 seconds
// Delay time in millisecs
static final int BROADCAST_DELAY = 10 * 1000;
@@ -379,24 +382,38 @@ class PackageManagerService extends IPackageManager.Stub {
if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" +
" DefaultContainerService");
Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
if (mContext.bindService(service, mDefContainerConn,
Context.BIND_AUTO_CREATE)) {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
mBound = true;
return true;
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return false;
}
private void disconnectService() {
mContainerService = null;
mBound = false;
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
mContext.unbindService(mDefContainerConn);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
}
PackageHandler(Looper looper) {
super(looper);
}
public void handleMessage(Message msg) {
try {
doHandleMessage(msg);
} finally {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
}
}
void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
if (DEBUG_SD_INSTALL) Log.i(TAG, "init_copy");
@@ -499,6 +516,7 @@ class PackageManagerService extends IPackageManager.Stub {
ArrayList components[];
int size = 0;
int uids[];
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPackages) {
if (mPendingBroadcasts == null) {
return;
@@ -530,15 +548,18 @@ class PackageManagerService extends IPackageManager.Stub {
sendPackageChangedBroadcast(packages[i], true,
(ArrayList<String>)components[i], uids[i]);
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
break;
}
case START_CLEANING_PACKAGE: {
String packageName = (String)msg.obj;
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPackages) {
if (!mSettings.mPackagesToBeCleaned.contains(packageName)) {
mSettings.mPackagesToBeCleaned.add(packageName);
}
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
startCleaningPackages();
} break;
case POST_INSTALL: {
@@ -598,10 +619,24 @@ class PackageManagerService extends IPackageManager.Stub {
Log.e(TAG, "MountService not running?");
}
} break;
case WRITE_SETTINGS: {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPackages) {
removeMessages(WRITE_SETTINGS);
mSettings.writeLP();
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
} break;
}
}
}
void scheduleWriteSettingsLocked() {
if (!mHandler.hasMessages(WRITE_SETTINGS)) {
mHandler.sendEmptyMessageDelayed(WRITE_SETTINGS, WRITE_SETTINGS_DELAY);
}
}
static boolean installOnSd(int flags) {
if (((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) ||
((flags & PackageManager.INSTALL_INTERNAL) != 0)) {
@@ -1633,32 +1668,84 @@ class PackageManagerService extends IPackageManager.Stub {
throw new SecurityException("No permission tree found for " + permName);
}
static boolean compareStrings(CharSequence s1, CharSequence s2) {
if (s1 == null) {
return s2 == null;
}
if (s2 == null) {
return false;
}
if (s1.getClass() != s2.getClass()) {
return false;
}
return s1.equals(s2);
}
static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) {
if (pi1.icon != pi2.icon) return false;
if (pi1.protectionLevel != pi2.protectionLevel) return false;
if (!compareStrings(pi1.name, pi2.name)) return false;
if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
// We'll take care of setting this one.
if (!compareStrings(pi1.packageName, pi2.packageName)) return false;
// These are not currently stored in settings.
//if (!compareStrings(pi1.group, pi2.group)) return false;
//if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
//if (pi1.labelRes != pi2.labelRes) return false;
//if (pi1.descriptionRes != pi2.descriptionRes) return false;
return true;
}
boolean addPermissionLocked(PermissionInfo info, boolean async) {
if (info.labelRes == 0 && info.nonLocalizedLabel == null) {
throw new SecurityException("Label must be specified in permission");
}
BasePermission tree = checkPermissionTreeLP(info.name);
BasePermission bp = mSettings.mPermissions.get(info.name);
boolean added = bp == null;
boolean changed = true;
if (added) {
bp = new BasePermission(info.name, tree.sourcePackage,
BasePermission.TYPE_DYNAMIC);
} else if (bp.type != BasePermission.TYPE_DYNAMIC) {
throw new SecurityException(
"Not allowed to modify non-dynamic permission "
+ info.name);
} else {
if (bp.protectionLevel == info.protectionLevel
&& bp.perm.owner.equals(tree.perm.owner)
&& bp.uid == tree.uid
&& comparePermissionInfos(bp.perm.info, info)) {
changed = false;
}
}
bp.protectionLevel = info.protectionLevel;
bp.perm = new PackageParser.Permission(tree.perm.owner,
new PermissionInfo(info));
bp.perm.info.packageName = tree.perm.info.packageName;
bp.uid = tree.uid;
if (added) {
mSettings.mPermissions.put(info.name, bp);
}
if (changed) {
if (!async) {
mSettings.writeLP();
} else {
scheduleWriteSettingsLocked();
}
}
return added;
}
public boolean addPermission(PermissionInfo info) {
synchronized (mPackages) {
if (info.labelRes == 0 && info.nonLocalizedLabel == null) {
throw new SecurityException("Label must be specified in permission");
}
BasePermission tree = checkPermissionTreeLP(info.name);
BasePermission bp = mSettings.mPermissions.get(info.name);
boolean added = bp == null;
if (added) {
bp = new BasePermission(info.name, tree.sourcePackage,
BasePermission.TYPE_DYNAMIC);
} else if (bp.type != BasePermission.TYPE_DYNAMIC) {
throw new SecurityException(
"Not allowed to modify non-dynamic permission "
+ info.name);
}
bp.protectionLevel = info.protectionLevel;
bp.perm = new PackageParser.Permission(tree.perm.owner,
new PermissionInfo(info));
bp.perm.info.packageName = tree.perm.info.packageName;
bp.uid = tree.uid;
if (added) {
mSettings.mPermissions.put(info.name, bp);
}
mSettings.writeLP();
return added;
return addPermissionLocked(info, false);
}
}
public boolean addPermissionAsync(PermissionInfo info) {
synchronized (mPackages) {
return addPermissionLocked(info, true);
}
}
@@ -6448,7 +6535,7 @@ class PackageManagerService extends IPackageManager.Stub {
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
mSettings.mPreferredActivities.addFilter(
new PreferredActivity(filter, match, set, activity));
mSettings.writeLP();
scheduleWriteSettingsLocked();
}
}
@@ -6519,7 +6606,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
if (clearPackagePreferredActivitiesLP(packageName)) {
mSettings.writeLP();
scheduleWriteSettingsLocked();
}
}
}
@@ -6608,18 +6695,28 @@ class PackageManagerService extends IPackageManager.Stub {
}
if (className == null) {
// We're dealing with an application/package level state change
if (pkgSetting.enabled == newState) {
// Nothing to do
return;
}
pkgSetting.enabled = newState;
} else {
// We're dealing with a component level state change
switch (newState) {
case COMPONENT_ENABLED_STATE_ENABLED:
pkgSetting.enableComponentLP(className);
if (!pkgSetting.enableComponentLP(className)) {
return;
}
break;
case COMPONENT_ENABLED_STATE_DISABLED:
pkgSetting.disableComponentLP(className);
if (!pkgSetting.disableComponentLP(className)) {
return;
}
break;
case COMPONENT_ENABLED_STATE_DEFAULT:
pkgSetting.restoreComponentLP(className);
if (!pkgSetting.restoreComponentLP(className)) {
return;
}
break;
default:
Slog.e(TAG, "Invalid new component state: " + newState);
@@ -7614,19 +7711,22 @@ class PackageManagerService extends IPackageManager.Stub {
installStatus = base.installStatus;
}
void enableComponentLP(String componentClassName) {
disabledComponents.remove(componentClassName);
enabledComponents.add(componentClassName);
boolean enableComponentLP(String componentClassName) {
boolean changed = disabledComponents.remove(componentClassName);
changed |= enabledComponents.add(componentClassName);
return changed;
}
void disableComponentLP(String componentClassName) {
enabledComponents.remove(componentClassName);
disabledComponents.add(componentClassName);
boolean disableComponentLP(String componentClassName) {
boolean changed = enabledComponents.remove(componentClassName);
changed |= disabledComponents.add(componentClassName);
return changed;
}
void restoreComponentLP(String componentClassName) {
enabledComponents.remove(componentClassName);
disabledComponents.remove(componentClassName);
boolean restoreComponentLP(String componentClassName) {
boolean changed = enabledComponents.remove(componentClassName);
changed |= disabledComponents.remove(componentClassName);
return changed;
}
int currentEnabledStateLP(String componentName) {