深入PMS源碼(二)—— APK的安裝和卸載源碼分析

1、應用程序安裝基礎

  • 單個APK程序安裝的過程
  1. 把原始的APk文件複製到程序相應的目錄文件下,對於第三方app複製到/data/app/目錄下
  2. 爲程序創建相應的數據目錄、提取dex文件、修改系統包管理信息
  • 程序安裝過程
  1. 在程序目錄下創建以包名稱命名的程序apk文件File
  2. 在data/data/目錄下創建應用程序的數據文件
  3. 將程序所有的信息寫入到配置文件package.xml文件中
  • HandlerParams主要實現子類
  1. InstallParams:完成要安裝程序的Copy工作
  2. MoveParams:實現對已安裝程序移動到外部保存目錄中
  abstract class HandlerParams { // 抽象類
4676        final static int MAX_RETRIES = 4; // 最多重試4次
4677        int retry = 0;
4678        final boolean startCopy() { // 提供文件Copy方法
4679            try {
4681                retry++;
4682                if (retry > MAX_RETRIES) { // 嘗試超過4次報錯
4684                    mHandler.sendEmptyMessage(MCS_GIVE_UP); // 超過4次後發送報錯信息,回調錯誤方法
4685                    handleServiceError();
4686                    return false;
4687                } else {
4688                    handleStartCopy(); // 子類需重寫,執行文件複製操作
                        res = true;
4691                }
4692            } catch (RemoteException e) {
4694                mHandler.sendEmptyMessage(MCS_RECONNECT);
4695            }
4696            handleReturnCode();
                return res;
4697        }
4699        final void serviceError() {
4701            handleServiceError();
4702            handleReturnCode();
4703        }
4704        abstract void handleStartCopy() throws RemoteException; // 抽象方法
4705        abstract void handleServiceError();
4706        abstract void handleReturnCode();
    }

由上面源碼知道,HandlerParams是抽象類,內部提供程序文件的複製功能,執行將安裝的apk文件複製到程序的制定安裝位置,程序調用startCopy()後開始執行文件賦值,具體賦值調用抽象方法handleStartCopy(),所以具體的功能子類需要重寫此方法,在copy發生異常時會發送Handler消息實現重試,最多重試4次後拋出異常;

2、PMS中APK安裝過程

程序的安裝執行到PMS中後,從Packagemanager的installpackage()方法開始,間接調用到PMS中installStage()函數,installStage()中首先創建InstallParams對象,保存要安裝的文件URI和其他信息,然後發送INIT_COPY異步消息啓動文件複製

public void installStage(.) {
4590        Message msg = mHandler.obtainMessage(INIT_COPY); // 創建INIT_COPY消息
4591        msg.obj = new InstallParams(packageURI, observer, flags,
4592                installerPackageName); // 創建InstallParams對象封裝安裝包屬性信息
4593        mHandler.sendMessage(msg);
4594    }

Handler在處理INIT_COPY消息時,根據mBound變量確定是否綁定了MSC服務,未綁定的先調用connectToService()執行綁定過程,然後將HandlerParams加入mPendingInstalls集合中等待執行,在服務綁定後發送MCS_BOUND消息,對於已經綁定的直接發送MSC_BOUND事件執行任務

                    if (!mBound) { // 1、判斷服務是否綁定
457                        if (!connectToService()) { // 2、執行Service綁定
459                            params.serviceError();
460                            return;
461                        } else {
464                            mPendingInstalls.add(idx, params); // 3、添加要執行的任務
465                        }
466                    } else {
467                        mPendingInstalls.add(idx, params); // 3、添加任務
470                        if (idx == 0) {
471                            mHandler.sendEmptyMessage(MCS_BOUND); // 4、就一個事件時,直接發送事件立即執行
472                        }
473                    }

在處理MCS_BOUND消息時,使用獲取的Binder服務從mPendingInstalls列表中取出安裝信息HandlerParams類中,

if (msg.obj != null) {
mContainerService = (IMediaContainerService) msg.obj; // 1、獲取對應的服務
}
HandlerParams params = mPendingInstalls.get(0); // 2、取出要安裝的參數
if (params != null) {
If(params.startCopy(){ // 3、執行Copy文件,最終執行到FileInstallArgs.copyApk()
    if (mPendingInstalls.size() > 0) {
        mPendingInstalls.remove(0);  // 刪除集合中的數據
    }
}; 
}

在Handler處理事件時,從消息msg中獲取IMediaContainerService服務對象,並從mPendingInstalls集合中獲取要執行的任務,此處獲取的是前面創建的InstallParams對象,然後調用params.startCopy()方法執行文件複製,按照HandlerParams的源碼程序會調用InstallParams.handleStartCopy()方法;

// InstallParams:實現全新安裝時的複製過程
 class InstallParams extends HandlerParams {
      public void handleStartCopy() throws RemoteException {
            mArgs = createInstallArgs(this); // 1、
4834        if (ret == PackageManager.INSTALL_SUCCEEDED) {
4837        ret = mArgs.copyApk(mContainerService, true); // 2、
4838        }
      }
}

在InstallParams中主要執行兩個過程:

  1. 根據Params類型創建InstallerArgs對象保存請求數據
  2. 調用InstallArgs.copyApk()方法實現複製
 private InstallArgs createInstallArgs(InstallParams params) {
4931        if (installOnSd(params.flags)) {
4932            return new SdInstallArgs(params);//複製到外部存儲時使用
4933        } else {
4934            return new FileInstallArgs(params); // 複製到內部存儲時使用,在FileInstallArgs內部調用IMediaContainerService服務執行Copy過程
    }
}

InstallArgs本身是一個抽象類,內部包含了很多屬性信息,它的實現類主要有兩個FileInstallArgs和SdInstallArgs,FileInstallArgs主要實現將文件複製到內部存儲,而SdInstallArgs執行復制到外部文件存儲,這裏會創建FileInstallArgs對象,在FileInstallArgs.copy()中直接調用doCopyApk();

  • FileInstallArgs.copyApk()
int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
// 1、創建臨時文件路徑:data/app/vmd.sessionId.tmp 文件目錄
final File tempDir = mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
codeFile = tempDir;
resourceFile = tempDir;
final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
    @Override
    public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
        try {
            final File file = new File(codeFile, name); // 創建apk文件
            final FileDescriptor fd = Os.open(file.getAbsolutePath(),
                    O_RDWR | O_CREAT, 0644);
            Os.chmod(file.getAbsolutePath(), 0644);
            return new ParcelFileDescriptor(fd); //2、以臨時File創建ParcelFileDescriptor對象,用於進程通信
        } 
    }
};
// 3、調用IMS方法實現文件Copy,將apk文件複製到temp文件中,然後將tmp文件複製到data/app/下,刪除臨時tmp文件
ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
}

在doCopyApk()中,首先在data/app/目錄下創建臨時目錄data/app/vmd.sessionId.tmp 文件,然後實例化IParcelFileDescriptorFactory.Stub()對象,並以臨時文件File創建ParcelFileDescriptor類用於Binder通信,最後調用imcs.copyPackage()執行文件複製,這裏imcs實際是DefaultContainerService的對象;

  • DefaultContainerService.copyPackage()
final File packageFile = new File(packagePath); // 1、獲取要複製的apk文件
pkg = PackageParser.parsePackageLite(packageFile, 0); // 2、parser程序包
return copyPackageInner(pkg, target); // 3、執行文件複製

private int copyPackageInner(PackageLite pkg, IParcelFileDescriptorFactory target)
        throws IOException, RemoteException {
    copyFile(pkg.baseCodePath, target, "base.apk”); // 1、複製apk文件
    if (!ArrayUtils.isEmpty(pkg.splitNames)) {
        for (int i = 0; i < pkg.splitNames.length; i++) {
            copyFile(pkg.splitCodePaths[i], target, "split_" + pkg.splitNames[i] + ".apk”); // 2、複製拆分的apk
        }
    }
return PackageManager.INSTALL_SUCCEEDED;
}

在copyPackage()方法中,首先根據文件路徑獲取apk文件,調用PackageParser解析apk文件,這裏的解析主要是看apk是否包含split apk,然後調用copyPackageInner執行文件複製工作,在copyPackageInner中調用copyFile()


private void copyFile(String sourcePath, IParcelFileDescriptorFactory target, String targetName)
        throws IOException, RemoteException {
    InputStream in = null;
    OutputStream out = null;
    try {
        in = new FileInputStream(sourcePath);
        out = new ParcelFileDescriptor.AutoCloseOutputStream(
        target.open(targetName, ParcelFileDescriptor.MODE_READ_WRITE)); // 回調target
        FileUtils.copy(in, out); // 執行文件複製,在tmp/base.apk/
    } finally {
        IoUtils.closeQuietly(out);
        IoUtils.closeQuietly(in);
    }
}

在copyFile()中,首先回調target的open()方法完成ParcelFileDescriptor的創建,然後調用FileUtils.copy()方法,將apk文件複製到tmp/base.apk/中,由前面的HandlerParam知道apk複製成功之後,回調InstallParams.handleReturnCode(),handleReturnCode()中直接調用processPendingInstall()方法

private void processPendingInstall(final InstallArgs args, final int currentStatus) {
    mHandler.post(new Runnable() { //1、mHandler發送延時任務
        public void run() {
            mHandler.removeCallbacks(this); //移除其它任務
            PackageInstalledInfo res = new PackageInstalledInfo();
            res.setReturnCode(currentStatus);
            res.uid = -1;
            res.pkg = null;
            res.removedInfo = null;
            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                args.doPreInstall(res.returnCode); //2、執行安裝前處理
                synchronized (mInstallLock) {
                    installPackageTracedLI(args, res); //3、執行安裝和解析
                }
                args.doPostInstall(res.returnCode, res.uid);//4、執行安裝後的掃尾工作
            }
    });
}

在processPendingInstall()中直接發送handler事件執行APK的安裝工作,在Handler事件中首先創建PackageInstalledInfo對象,保存安裝的狀態,在複製成功後執行以下操作:

  1. 調用args.doPreInstall()執行安裝apk前準備;
  2. 調用installPackageTracedLI(args, res)執行apk的解析和安裝工作
  3. 調用args.doPostInstall()執行apk文件安裝完成後的工作
  • args.doPreInstall(res.returnCode):如果複製狀態不爲Success,則清除複製的文件
int doPreInstall(int status) {
    if (status != PackageManager.INSTALL_SUCCEEDED) {//未複製成功清除文件
        cleanUp();
    }
    return status; 
}
  • installPackageTracedLI()中直接調用installPackageLI()
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
    final int installFlags = args.installFlags;
    final String installerPackageName = args.installerPackageName;
    final File tmpPackageFile = new File(args.getCodePath());
    PackageParser pp = new PackageParser();
    pkg = pp.parsePackage(tmpPackageFile, parseFlags); // 1、解析apk文件
//檢查apk
//校驗簽名
// 2、/data/app/vmdl18300388.tmp/base.apk,重命名爲/data/app/包名-1/base.apk。
if (!args.doRename(res.returnCode, pkg, oldCodePath)) { 
    return;
}
if (replace) {
replacePackageLIF(pkg, parseFlags, scanFlags, args.user,
            installerPackageName, res, args.installReason); // 3、替換apk
} else {
installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
        args.user, installerPackageName, volumeUuid, res, args.installReason); // 3、安裝新的apk
}
}

在installPackageLI()中主要執行以下操作:

  1. 創建PackageParser對象解析複製的臨時apk文件;
  2. 檢查複製的apk文件並校驗簽名信息等;
  3. 將複製的apk文件目錄,重命名爲以包名爲目錄的文件
  4. 確認是已安裝的apk更新還是新安裝的app,對於新安裝的app執行installNewPackageLIF()方法
  • installNewPackageLIF():安裝新的apk
PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags, // 重新掃描apk文件
        System.currentTimeMillis(), user);
updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason); // 更新Setting
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
    prepareAppDataAfterInstallLIF(newPackage); // 爲安裝好的App準備數據
}

在installNewPackageLIF()中首先調用scanPackageTracedLI()重新掃描apk文件,scanPackageTracedLI內部會調用scanPackageNewLI()提交解析結果,將解析的結果Package對象添加到PMS的屬性中,詳細流程參見深入PMS源碼(一)—— PMS的啓動過程和執行流程,在安裝完成後調用updateSettingsLI()更新mSetting屬性,最後調用prepareAppDataAfterInstallLIF()爲新安裝的程序準備數據;

scannedPkg = scanPackageNewLI(pkg, parseFlags, scanFlags, currentTime, user);

到此程序的安裝就完成了,上面主要介紹了Android系統是如何實現安裝和文件複製的,在複製完成後,就會向PMS啓動過程一樣解析和處理apk文件;

3、應用程序的卸載過程

  • 應用程序的卸載
packageManager.packageInstaller.uninstall() //卸載程序

深入PMS源碼(一)—— PMS的啓動過程和執行流程分析知道此處packageManager獲取的是ApplicationPackageManager,而packageInstaller是在ApplicationPackageManager內部實例化的PackageInstaller的對象

@Override
    public PackageInstaller getPackageInstaller() {
        synchronized (mLock) {
            if (mInstaller == null) {
                try {
                    mInstaller = new PackageInstaller(mPM.getPackageInstaller(),
                            mContext.getPackageName(), mContext.getUserId());
                }
            }
            return mInstaller;
        }
    }

在創建PackageInstaller對象中,調用mPM.getPackageInstaller()調用PMS中方法獲取PackageInstallerService對象,並將其封裝在PackageInstaller對象中,程序繼續調用PackageInstaller.uninstall()中

public void uninstall(@NonNull String packageName, @DeleteFlags int flags,
            @NonNull IntentSender statusReceiver) {
        uninstall(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
                flags, statusReceiver);
    }

uninstall()中首先根據傳入的包名創建VersionedPackage對象,然後繼續調用uninstall的重載方法

 @RequiresPermission(anyOf = {
            Manifest.permission.DELETE_PACKAGES,
            Manifest.permission.REQUEST_DELETE_PACKAGES})
    public void uninstall(@NonNull VersionedPackage versionedPackage, @DeleteFlags int flags,
            @NonNull IntentSender statusReceiver) {
        try {
            mInstaller.uninstall(versionedPackage, mInstallerPackageName,
                    flags, statusReceiver, mUserId); //2、
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

在uninstall()中直接調用mInstaller.uninstall(),這裏的mInstaller對象就是在創建PackageInstaller時傳入的第一個參數,即PMS中實例話的PackageInstallerService對象,PackageInstallerService實現了IPackageInstaller.Stub類,可用於進程間通信

public class PackageInstallerService extends IPackageInstaller.Stub {
 @Override
    public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,IntentSender statusReceiver, int userId) throws RemoteException {
         mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall"); // 1、檢查權限
          final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
                statusReceiver, versionedPackage.getPackageName(),
                isDeviceOwnerOrAffiliatedProfileOwner, userId);  //2、
                     
                }
                if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)== PackageManager.PERMISSION_GRANTED) {
            mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
        } 
}

在PackageInstallerService.install()權限中,主要執行3個流程:

  1. 創建PackageDeleteObserverAdapter對象,用於接收響應刪除的結果
  2. 檢查當前程序是否具有刪除權限
  3. 調用PMS的deletePackageVersioned()方法執行程序的卸載

從上面分析應用程序真正開始卸載,是從PackageManager的deletePackageAsUser()函數開始,間接調用PMS的deletePackageVersioned()方法

@Override
public void deletePackageVersioned(VersionedPackage versionedPackage,
  final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
              mHandler.post(new Runnable() { //發送Handler事件
            public void run() {
                mHandler.removeCallbacks(this); // 移除事件
                int returnCode;
                final PackageSetting ps = mSettings.mPackages.get(internalPackageName);//獲取PackageSettings對象
                boolean doDeletePackage = true;
                if (ps != null) {
                    final boolean targetIsInstantApp =
                            ps.getInstantApp(UserHandle.getUserId(callingUid));
                    doDeletePackage = !targetIsInstantApp
                            || canViewInstantApps;
                }
                if (doDeletePackage) {
                    if (!deleteAllUsers) {
                        returnCode = deletePackageX(internalPackageName, versionCode,
                                userId, deleteFlags);
                    } 
               }
                try {
       observer.onPackageDeleted(packageName, returnCode, null);// 刪除後回調
                } 
            } 
        }); 
}

在deletePackageVersioned()中發送Post事件執行異步刪除操作,在Handler事件中調用deletePackageX()方法

 int deletePackageX(String packageName, long versionCode, int userId, int deleteFlags) {
  final PackageRemovedInfo info = new PackageRemovedInfo(this);
   if (isPackageDeviceAdmin(packageName, removeUser)) {
            Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
        }
info.origUsers = uninstalledPs.queryInstalledUsers(allUsers, true);
 res = deletePackageLIF(packageName, UserHandle.of(removeUser), true, allUsers,
                        deleteFlags | PackageManager.DELETE_CHATTY, info, true, null);

}

在deletePackageX()中首先判斷要卸載的程序是否是admin管理的,如果是則直接return,如果不是則執行deletePackageLIF()方法繼續卸載程序

  • deletePackageLIF()
 p = mPackages.get(packageName); //1、獲取保存應用程序的Package對象
if (isSystemApp(p)) {
ret = deleteSystemPackageLI(p, flags, outInfo, writeSettings); //2、如果是系統app
6376        } else {
// 3、處理第三方app卸載
ret = deleteInstalledPackageLIF(p, deleteCodeAndResources, flags, outInfo,
6381                    writeSettings);
6382        }

deletePackageLIF()中根據app類型區分系統app和第三方app,執行不同的卸載程序,對於第三方app執行deleteInstalledPackageLIF()方法,在deleteInstalledPackageLIF()中也是直接調用removePackageDataLI()

  • removePackageDataLIF()
  private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo,int flags, boolean writeSettings) {
6183        String packageName = p.packageName;
6187        removePackageLI(p, (flags&REMOVE_CHATTY) != 0); // 1、移除mPackages集合中保存的package對象

if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
            final PackageParser.Package resolvedPkg;
                resolvedPkg = new PackageParser.Package(ps.name);
                resolvedPkg.setVolumeUuid(ps.volumeUuid);
            }
            destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL,
                    StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); // 2、調用Installer執行清除/data/app/目錄下的文件信息
            destroyAppProfilesLIF(resolvedPkg, UserHandle.USER_ALL);
            //3、發送包清理事件
            schedulePackageCleaning(packageName, UserHandle.USER_ALL, true);
        }

6210        synchronized (mPackages) {
6211            if (deletedPs != null) {
6212                if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
6213                    if (outInfo != null) {
6214                        outInfo.removedUid = mSettings.removePackageLPw(packageName); // 4、移除mSetting中保存的數據
6215                    }
6216                    if (deletedPs != null) {
                                mHandler.post(new Runnable() {
                                    @Override
                                    public void run() {//5、發送事件殺死進程信息
                                        killApplication(deletedPs.name, deletedPs.appId,
                                                KILL_APP_REASON_GIDS_CHANGED);
                                    }
                                });
6221                        }
6222                    }
6223                } 
  if (writeSettings) {
    mSettings.writeLPr(); // 6、寫入mSettings信息,更新Package.xml文件
  }
}

在removePackageDataLIF()方法中執行了卸載刪除的重要操作,具體如下:

  1. 調用removePackageLI()刪除mPackages集合中保存的次apk的解析對象Package,在removePackageLI中會調用cleanPackageDataStructuresLILPw(),刪除此PMS中保存的此應用程序中的四大組件信息
  void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) {
        int N = pkg.providers.size();
         for (i=0; i<N; i++) {
            PackageParser.Provider p = pkg.providers.get(i);
            mProviders.removeProvider(p);
        }
        
        N = pkg.services.size();
        r = null;
        for (i=0; i<N; i++) {
            PackageParser.Service s = pkg.services.get(i);
            mServices.removeService(s);
        }
        }
        ......
}
  1. 調用destroyAppDataLIF()方法,使用Installer刪除此應用程序/data/app/目錄下的安裝包信息
  2. 調用schedulePackageCleaning()發送START_CLEANING_PACKAGE事件執行外部使用數據刪除
  3. 刪除mSetting中保存此程序的PackageSetting對象
  4. 發送Handler事件調用killApplication()殺死應用進程
  5. 調用mSettings.writeLPr()將mSettings信息寫入配置文件package.xml中
  • destroyAppDataLIF()

在destroyAppDataLIF()中直接調用destroyAppDataLeafLIF()方法,destroyAppDataLeafLIF中主要調用mInstaller中方法執行刪除,刪除應用數據之後調用mDexManager通知刪除結束;

private void destroyAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
        final PackageSetting ps;
        synchronized (mPackages) {
            ps = mSettings.mPackages.get(pkg.packageName);//獲取PackageSetting對象
        }
        for (int realUserId : resolveUserIds(userId)) {
            final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
            try { // 調用mInstaller執行文件數據刪除
        mInstaller.destroyAppData(pkg.volumeUuid, pkg.packageName, realUserId, flags,
                        ceDataInode);
            } 
        mDexManager.notifyPackageDataDestroyed(pkg.packageName, userId);
        }
    }
  • schedulePackageCleaning():執行mSetting中信息和程序數據文件的刪除
void schedulePackageCleaning(String packageName, int userId, boolean andCode) {
        final Message msg = mHandler.obtainMessage(START_CLEANING_PACKAGE,
                userId, andCode ? 1 : 0, packageName); // 創建Message對象
            msg.sendToTarget(); // 發送事件
    }

case START_CLEANING_PACKAGE: {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
                    final String packageName = (String)msg.obj;
                    final int userId = msg.arg1;
                    final boolean andCode = msg.arg2 != 0;
                    synchronized (mPackages) {
                            mSettings.addPackageToCleanLPw(
                                    new PackageCleanItem(userId, packageName, andCode));
                                    }          Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
startCleaningPackages();
                } break;

在schedulePackageCleaning()創建Message對象併發送事件,在Handler處理事件時首先調用mSetting將要刪除的信息保存在Settings的mPackagesToBeCleaned集合中,然後調用startCleaningPackages()啓動本地服務DefaultContainerService服務,

@Override
    protected void onHandleIntent(Intent intent) {
        if (PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE.equals(intent.getAction())) {
            final IPackageManager pm = IPackageManager.Stub.asInterface(
                    ServiceManager.getService("package")); // 獲取PMS對象
            PackageCleanItem item = null;
            try {
                while ((item = pm.nextPackageToClean(item)) != null) {
                    final UserEnvironment userEnv = new UserEnvironment(item.userId);
   //刪除/Android/data/xxxx/下文件信息
eraseFiles(userEnv.buildExternalStorageAppDataDirs(item.packageName));
   //刪除/Android/media/xxxx/下文件信息
eraseFiles(userEnv.buildExternalStorageAppMediaDirs(item.packageName));
                }
            } 
        }
    }

在本地服務的onHandleIntent()中調用PMS的nextPackageToClean()獲取剛纔加入的mSetting中的mPackagesToBeCleaned集合,並遍歷集合一次從中取出要卸載刪除的數據包,並獲取文件路徑執行eraseFiles()刪除文件;

void eraseFiles(File path) {
        if (path.isDirectory()) {
            String[] files = path.list();
            if (files != null) {
                for (String file : files) {
                    eraseFiles(new File(path, file)); // 遞歸刪除目錄下文件
                }
            }
        }
        path.delete(); // 刪除數據
    }

到此應用程序的app安裝文件和使用中產生的數據文件都已被刪除,且配置文件已更新完成,此時會回調deletePackageVersioned()中的 observer.onPackageDeleted(packageName, returnCode, null)方法通知刪除結果,這裏回調的是PackageDeleteObserverAdapter類中

@Override
        public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
            if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) {
                NotificationManager notificationManager = (NotificationManager)
                        mContext.getSystemService(Context.NOTIFICATION_SERVICE);
                notificationManager.notify(basePackageName,
                        SystemMessage.NOTE_PACKAGE_STATE,
                        mNotification);
            }
            final Intent fillIn = new Intent();
            fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
                    PackageManager.deleteStatusToPublicStatus(returnCode));
            fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
                    PackageManager.deleteStatusToString(returnCode, msg));
            fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
            try {
                mTarget.sendIntent(mContext, 0, fillIn, null, null);
            } catch (SendIntentException ignored) {
            }
        }

在onPackageDeleted()中,首先調用NotificationManager中方法發送notify()通知安裝成功,然後創建Intent對象並回調mTarget.sendIntent(),這裏的mTarget對象其實就是卸載最開始時調用uninstall()方法傳入的第二個參數,即IntentSender對象,用於接收刪除的結果;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章