卸载流程
4.1 卸载的调用堆栈
看看卸载的调用堆栈
05-01 08:50:27.174: D/PackageManagerService(1107): com.android.server.pm.PackageManagerService.deletePackage(PackageManagerService.java:14445)
05-01 08:50:27.174: D/PackageManagerService(1107): com.android.server.pm.PackageManagerService.deletePackageAsUser(PackageManagerService.java:14432)
05-01 08:50:27.174: D/PackageManagerService(1107): android.content.pm.IPackageManager$Stub.onTransact(IPackageManager.java:1038)
05-01 08:50:27.174: D/PackageManagerService(1107): com.android.server.pm.PackageManagerService.onTransact(PackageManagerService.java:3144)
05-01 08:50:27.174: D/PackageManagerService(1107): android.os.Binder.execTransact(Binder.java:458)
在桌面进行卸载的时候,发送卸载命令给PMS
通过binder调用到PMS的deletePackageAsUser
接着调用deletePackage
在deletePackage里
// Queue up an async operation since the package deletion may take a little while.
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
final int returnCode = deletePackageX(packageName, userId, flags);
if (observer != null) {
try {
observer.onPackageDeleted(packageName, returnCode, null);
} catch (RemoteException e) {
Log.i(TAG, "Observer no longer exists.");
} //end catch
} //end if
} //end run
});
调到了deletePackageX
4.2 deletePackageX
private int deletePackageX(String packageName, int userId, int flags) {
final PackageRemovedInfo info = new PackageRemovedInfo();
final boolean res;
final UserHandle removeForUser = (flags & PackageManager.DELETE_ALL_USERS) != 0
? UserHandle.ALL : new UserHandle(userId);
if (isPackageDeviceAdmin(packageName, removeForUser.getIdentifier())) {
Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
}
boolean removedForAllUsers = false;
boolean systemUpdate = false;
// for the uninstall-updates case and restricted profiles, remember the per-
// userhandle installed state
int[] allUsers;
boolean[] perUserInstalled;
synchronized (mPackages) {
PackageSetting ps = mSettings.mPackages.get(packageName);
allUsers = sUserManager.getUserIds();
perUserInstalled = new boolean[allUsers.length];
for (int i = 0; i < allUsers.length; i++) {
perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false;
}
}
synchronized (mInstallLock) {
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
res = deletePackageLI(packageName, removeForUser,
true, allUsers, perUserInstalled,
flags | REMOVE_CHATTY, info, true);
systemUpdate = info.isRemovedPackageSystemUpdate;
if (res && !systemUpdate && mPackages.get(packageName) == null) {
removedForAllUsers = true;
}
if (DEBUG_REMOVE) Slog.d(TAG, "delete res: systemUpdate=" + systemUpdate
+ " removedForAllUsers=" + removedForAllUsers);
}
if (res) {
info.sendBroadcast(true, systemUpdate, removedForAllUsers);
// If the removed package was a system update, the old system package
// was re-enabled; we need to broadcast this information
if (systemUpdate) {
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, info.removedAppId >= 0
? info.removedAppId : info.uid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
String category = null;
if (info.isThemeApk) {
category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE;
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, category,
extras, null, null, null);
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, category,
extras, null, null, null);
} else {
}
}
// Force a gc here.
Runtime.getRuntime().gc();
// Delete the resources here after sending the broadcast to let
// other processes clean up before deleting resources.
if (info.args != null) {
synchronized (mInstallLock) {
info.args.doPostDeleteLI(true);
}
}
return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
}
这里调用到了info.args.doPostDeleteLI(true);,
由于info.args是抽象类InstallArgs,static abstract class InstallArgs
卸载的是手机内部存储里的应用时,执行的是FileInstallArgs类的doPostDeleteLI方法
info.args是在这里得到的
private boolean deleteInstalledPackageLI(PackageSetting ps,
boolean deleteCodeAndResources, int flags,
int[] allUserHandles, boolean[] perUserInstalled,
PackageRemovedInfo outInfo, boolean writeSettings) {
if (outInfo != null) {
outInfo.uid = ps.appId;
}
// Delete package data from internal structures and also remove data if flag is set
removePackageDataLI(ps, allUserHandles, perUserInstalled, outInfo, flags, writeSettings);
// Delete application code and resources
if (deleteCodeAndResources && (outInfo != null)) {
outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
}
return true;
}
createInstallArgsForExisting
/**
* Create args that describe an existing installed package. Typically used
* when cleaning up old installs, or used as a move source.
*/
private InstallArgs createInstallArgsForExisting(int installFlags, String codePath,
String resourcePath, String[] instructionSets) {
final boolean isInAsec;
if (installOnExternalAsec(installFlags)) {
/* Apps on SD card are always in ASEC containers. */
isInAsec = true;
} else if (installForwardLocked(installFlags)
&& !codePath.startsWith(mDrmAppPrivateInstallDir.getAbsolutePath())) {
/*
* Forward-locked apps are only in ASEC containers if they're the
* new style
*/
isInAsec = true;
} else {
isInAsec = false;
}
if (isInAsec) {
return new AsecInstallArgs(codePath, instructionSets,
installOnExternalAsec(installFlags), installForwardLocked(installFlags));
} else {
return new FileInstallArgs(codePath, resourcePath, instructionSets);
}
}
4.3 SD卡里应用的卸载
卸载SD卡里的应用时,执行到了AsecInstallArgs类的
boolean doPostDeleteLI(boolean delete) {
if (DEBUG_SD_INSTALL) Slog.i(TAG, "doPostDeleteLI() del=" + delete);
final List<String> allCodePaths = getAllCodePaths();
boolean mounted = PackageHelper.isContainerMounted(cid);
if (mounted) {
// Unmount first
if (PackageHelper.unMountSdDir(cid)) {
mounted = false;
}
}
if (!mounted && delete) {
cleanUpResourcesLI(allCodePaths);
}
return !mounted;
}
在if (PackageHelper.unMountSdDir(cid)) 里,调用到MountService.java里的
public int unmountSecureContainer(String id, boolean force) {
Slog.i(TAG, "unmountSecureContainer, id=" + id
+ ", force=" + force);
enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
waitForReady();
warnOnNotMounted();
synchronized (mAsecMountSet) {
if (!mAsecMountSet.contains(id)) {
Slog.i(TAG, "OperationFailedStorageNotMounted");
return StorageResultCode.OperationFailedStorageNotMounted;
}
}
/*
* Force a GC to make sure AssetManagers in other threads of the
* system_server are cleaned up. We have to do this since AssetManager
* instances are kept as a WeakReference and it's possible we have files
* open on the external storage.
*/
Runtime.getRuntime().gc();
System.runFinalization();
int rc = StorageResultCode.OperationSucceeded;
try {
final Command cmd = new Command("asec", "unmount", id);
if (force) {
cmd.appendArg("force");
}
mConnector.execute(cmd);
} catch (NativeDaemonConnectorException e) {
int code = e.getCode();
if (code == VoldResponseCode.OpFailedStorageBusy) {
rc = StorageResultCode.OperationFailedStorageBusy;
} else {
rc = StorageResultCode.OperationFailedInternalError;
}
}
if (rc == StorageResultCode.OperationSucceeded) {
synchronized (mAsecMountSet) {
mAsecMountSet.remove(id);
}
}
return rc;
}
public boolean isSecureContainerMounted(String id) {
enforcePermission(android.Manifest.permission.ASEC_ACCESS);
waitForReady();
warnOnNotMounted();
synchronized (mAsecMountSet) {
return mAsecMountSet.contains(id);
}
}
public int renameSecureContainer(String oldId, String newId) {
Slog.i(TAG, "renameSecureContainer, oldId=" + oldId
+ ", newId=" + newId);
enforcePermission(android.Manifest.permission.ASEC_RENAME);
waitForReady();
warnOnNotMounted();
synchronized (mAsecMountSet) {
/*
* Because a mounted container has active internal state which cannot be
* changed while active, we must ensure both ids are not currently mounted.
*/
if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
return StorageResultCode.OperationFailedStorageMounted;
}
}
int rc = StorageResultCode.OperationSucceeded;
try {
mConnector.execute("asec", "rename", oldId, newId);
} catch (NativeDaemonConnectorException e) {
rc = StorageResultCode.OperationFailedInternalError;
}
return rc;
}
和vold进程进行通信
发送类似SND -> {35 asec unmount com.dannyAndroid.stuinfo-2 force}的指令
让vold进行umount操作
vold在处理的时候,发现base.apk被占用,就向system_server发送了kill信号,导致重启,见1.1
05-01 09:33:54.881: D/VoldConnector(1107): SND -> {33 asec unmount com.UCMobile-2 force}
从system_server调到pid 385
05-01 09:33:54.881: D/FrameworkListener(385): dispatchCommand data = (33 asec unmount com.UCMobile-2 force)
05-01 09:33:54.881: D/VoldCmdListener(385): asec unmount com.UCMobile-2 force