android 6.0卸载应用程序,Android 6.0 PKMS 卸載刪除app

PKMS中卸載應用是通過deletePackage函數來執行,這個函數主要是調用了一些Observer回調,然后調用了deletePackageX函數。

publicvoiddeletePackage(final String packageName,

final IPackageDeleteObserver2 observer, final intuserId, finalintflags) {

mContext.enforceCallingOrSelfPermission(

android.Manifest.permission.DELETE_PACKAGES, null);

Preconditions.checkNotNull(packageName);

Preconditions.checkNotNull(observer);

final intuid = Binder.getCallingUid();

if(UserHandle.getUserId(uid) != userId) {

mContext.enforceCallingPermission(

android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,

"deletePackage for user "+ userId);

}

if(isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) {

try{

observer.onPackageDeleted(packageName,//回調

PackageManager.DELETE_FAILED_USER_RESTRICTED, null);

} catch(RemoteException re) {

}

return;

}

boolean uninstallBlocked = false;

if((flags & PackageManager.DELETE_ALL_USERS) != 0) {

int[] users = sUserManager.getUserIds();

for(inti = 0; i 

if(getBlockUninstallForUser(packageName, users[i])) {

uninstallBlocked = true;

break;

}

}

} else{

uninstallBlocked = getBlockUninstallForUser(packageName, userId);

}

if(uninstallBlocked) {

try{

observer.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_OWNER_BLOCKED,

null);

} catch(RemoteException re) {

}

return;

}

if(DEBUG_REMOVE) {

Slog.d(TAG, "deletePackageAsUser: pkg="+ packageName +" user="+ userId);

}

// Queue up an async operation since the package deletion may take a little while.

mHandler.post(newRunnable() {//異步調用deletePackageX函數

publicvoidrun() {

mHandler.removeCallbacks(this);

final intreturnCode = 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函數,主要是調用deletePackageLI函數繼續執行,關鍵當返回的info不為空就調用info.args.doPostDeleteLI(true)刪除應用。



privateintdeletePackageX(String packageName,intuserId,intflags) {

......

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);

}

......

// 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);//刪除資源、apk等

}

}

returnres ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;

}

我們來看deletePackageLI函數,如果只有data,直接調用removePackageDataLI函數。如果是系統應用調用deleteSystemPackageLI,不是調用deleteInstalledPackageLI函數。

privateboolean deletePackageLI(String packageName, UserHandle user,

boolean deleteCodeAndResources, int[] allUserHandles, boolean[] perUserInstalled,

intflags, PackageRemovedInfo outInfo,

boolean writeSettings) {

......

if(dataOnly) {

// Delete application data first

if(DEBUG_REMOVE) Slog.d(TAG,"Removing package data only");

removePackageDataLI(ps, null, null, outInfo, flags, writeSettings);

returntrue;

}

boolean ret = false;

if(isSystemApp(ps)) {

if(DEBUG_REMOVE) Slog.d(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(ps, allUserHandles, perUserInstalled,

flags, outInfo, writeSettings);

} else{

if(DEBUG_REMOVE) Slog.d(TAG,"Removing non-system package:"+ ps.name);

// Kill application pre-emptively especially for apps on sd.

killApplication(packageName, ps.appId, "uninstall pkg");

ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags,

allUserHandles, perUserInstalled,

outInfo, writeSettings);

}

returnret;

}

卸載系統應用

為什么會有卸載系統應用呢,當我們調用scanPackageLI掃描目錄時有時候失敗,也需要調用deletePackageLI來刪除apk,這個時候就會有系統應用了。

privateboolean deleteSystemPackageLI(PackageSetting newPs,

int[] allUserHandles, boolean[] perUserInstalled,

intflags, PackageRemovedInfo outInfo, boolean writeSettings) {

final boolean applyUserRestrictions

= (allUserHandles != null) && (perUserInstalled != 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) {

disabledPs = mSettings.getDisabledSystemPkgLPr(newPs.name);

}

if(DEBUG_REMOVE) Slog.d(TAG,"deleteSystemPackageLI: newPs="+ newPs

+ " disabledPs="+ disabledPs);

if(disabledPs == null) {

Slog.w(TAG, "Attempt to delete unknown system package "+ newPs.name);

returnfalse;

} elseif(DEBUG_REMOVE) {

Slog.d(TAG, "Deleting system pkg from data partition");

}

// Delete the updated package

outInfo.isRemovedPackageSystemUpdate = true;

if(disabledPs.versionCode 

// Delete data for downgrades

flags &= ~PackageManager.DELETE_KEEP_DATA;//是否保留資源

} else{

// Preserve data by setting flag

flags |= PackageManager.DELETE_KEEP_DATA;

}

boolean ret = deleteInstalledPackageLI(newPs, true, flags,//卸載apk

allUserHandles, perUserInstalled, outInfo, writeSettings);

if(!ret) {

returnfalse;

}

// writer

synchronized (mPackages) {

// Reinstate the old system package

mSettings.enableSystemPackageLPw(newPs.name);

// Remove any native libraries from the upgraded package.

NativeLibraryHelper.removeNativeBinariesLI(newPs.legacyNativeLibraryPathString);

}

// Install the system package

intparseFlags = PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM;

if(locationIsPrivileged(disabledPs.codePath)) {

parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;

}

final PackageParser.Package newPkg;

try{

newPkg = scanPackageLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0, null);//重新apk掃描目錄

} catch(PackageManagerException e) {

Slog.w(TAG, "Failed to restore system package:"+ newPs.name +": "+ e.getMessage());

returnfalse;

}

// writer

synchronized (mPackages) {

PackageSetting ps = mSettings.mPackages.get(newPkg.packageName);

// Propagate the permissions state as we do not want to drop on the floor

// runtime permissions. The update permissions method below will take

// care of removing obsolete permissions and grant install permissions.

ps.getPermissionsState().copyFrom(newPs.getPermissionsState());

updatePermissionsLPw(newPkg.packageName, newPkg,

UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG);

if(applyUserRestrictions) {

if(DEBUG_REMOVE) {

Slog.d(TAG, "Propagating install state across reinstall");

}

for(inti = 0; i 

if(DEBUG_REMOVE) {

Slog.d(TAG, "    user "+ allUserHandles[i]

+ " => "+ perUserInstalled[i]);

}

ps.setInstalled(perUserInstalled[i], allUserHandles[i]);

mSettings.writeRuntimePermissionsForUserLPr(allUserHandles[i], false);

}

// Regardless of writeSettings we need to ensure that this restriction

// state propagation is persisted

mSettings.writeAllUsersPackageRestrictionsLPr();

}

// can downgrade to reader here

if(writeSettings) {

mSettings.writeLPr();//更新packages.xml

}

}

returntrue;

}

卸載系統應用,最后也是調用deleteInstalledPackageLI來完成卸載的,我們來看下這個函數。

卸載普通應用

卸載普通應用就直接調用了deleteInstalledPackageLI函數

privateboolean deleteInstalledPackageLI(PackageSetting ps,

boolean deleteCodeAndResources, intflags,

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);

}

returntrue;

}

我們先看removePackageDataLI函數,就是刪除各種資源,但是我們沒看到刪除apk文件。

privatevoidremovePackageDataLI(PackageSetting ps,

int[] allUserHandles, boolean[] perUserInstalled,

PackageRemovedInfo outInfo, intflags, boolean writeSettings) {

String packageName = ps.name;

if(DEBUG_REMOVE) Slog.d(TAG,"removePackageDataLI: "+ ps);

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(outInfo != null) {

outInfo.removedPackage = packageName;

outInfo.removedUsers = deletedPs != null

? deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true)

: null;

}

}

if((flags&PackageManager.DELETE_KEEP_DATA) == 0) {

removeDataDirsLI(ps.volumeUuid, packageName);// 卸載data目錄

schedulePackageCleaning(packageName, UserHandle.USER_ALL, true);

}

// writer

synchronized (mPackages) {

if(deletedPs != null) {

if((flags&PackageManager.DELETE_KEEP_DATA) == 0) {

clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);

clearDefaultBrowserIfNeeded(packageName);

if(outInfo != null) {

mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);

outInfo.removedAppId = mSettings.removePackageLPw(packageName);

}

updatePermissionsLPw(deletedPs.name, null, 0);

if(deletedPs.sharedUser != null) {

// Remove permissions associated with package. Since runtime

// permissions are per user we have to kill the removed package

// or packages running under the shared user of the removed

// package if revoking the permissions requested only by the removed

// package is successful and this causes a change in gids.

for(intuserId : UserManagerService.getInstance().getUserIds()) {

final intuserIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs,

userId);

if(userIdToKill == UserHandle.USER_ALL

|| userIdToKill >= UserHandle.USER_OWNER) {

// If gids changed for this user, kill all affected packages.

mHandler.post(newRunnable() {

@Override

publicvoidrun() {

// This has to happen with no lock held.

killApplication(deletedPs.name, deletedPs.appId,

KILL_APP_REASON_GIDS_CHANGED);

}

});

break;

}

}

}

clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL);

}

// make sure to preserve per-user disabled state if this removal was just

// a downgrade of a system app to the factory package

if(allUserHandles != null && perUserInstalled != null) {

if(DEBUG_REMOVE) {

Slog.d(TAG, "Propagating install state across downgrade");

}

for(inti = 0; i 

if(DEBUG_REMOVE) {

Slog.d(TAG, "    user "+ allUserHandles[i]

+ " => "+ perUserInstalled[i]);

}

ps.setInstalled(perUserInstalled[i], allUserHandles[i]);

}

}

}

// can downgrade to reader

if(writeSettings) {

// Save settings now

mSettings.writeLPr();//更新packages.xml

}

}

if(outInfo != null) {

// A user ID was deleted here. Go through all users and remove it

// from KeyStore.

removeKeystoreDataIfNeeded(UserHandle.USER_ALL, outInfo.removedAppId);

}

我們再來看deleteInstalledPackageLI函數,最后一段代碼,

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);

}

我們來看下這個函數,如果不是安裝在sd卡上,最后新建一個FileInstallArgs對象。

privateInstallArgs createInstallArgsForExisting(intinstallFlags, String codePath,

String resourcePath, String[] instructionSets) {

final boolean isInAsec;

if(installOnExternalAsec(installFlags)) {

/* Apps on SD card are always in ASEC containers. */

isInAsec = true;

} elseif(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) {

returnnewAsecInstallArgs(codePath, instructionSets,

installOnExternalAsec(installFlags), installForwardLocked(installFlags));

} else{

returnnewFileInstallArgs(codePath, resourcePath, instructionSets);

}

}

最后返回到deletePackageX函數,最后調用如下代碼,直接到FileInstallArgs的doPostDeleteLI函數。

if(info.args != null) {

synchronized (mInstallLock) {

info.args.doPostDeleteLI(true);

}

}

doPostDeleteLI函數如下:

boolean doPostDeleteLI(booleandelete) {

// XXX err, shouldn't we respect the delete flag?

cleanUpResourcesLI();

returntrue;

}

cleanUpResourcesLI函數會刪除資源和代碼文件,dex文件

voidcleanUpResourcesLI() {

// Try enumerating all code paths before deleting

List allCodePaths = Collections.EMPTY_LIST;

if(codeFile != null && codeFile.exists()) {

try{

final PackageLite pkg = PackageParser.parsePackageLite(codeFile, 0);

allCodePaths = pkg.getAllCodePaths();

} catch(PackageParserException e) {

// Ignored; we tried our best

}

}

cleanUp();

removeDexFiles(allCodePaths, instructionSets);

}

cleanUp函數就是刪除apk文件。

privateboolean cleanUp() {

if(codeFile == null || !codeFile.exists()) {

returnfalse;

}

if(codeFile.isDirectory()) {

mInstaller.rmPackageDir(codeFile.getAbsolutePath());

} else{

codeFile.delete();

}

if(resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {

resourceFile.delete();

}

returntrue;

}

時序圖

7ed769cffa67460cf542f5a727f7c6a9.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值