当前位置:   article > 正文

PackageManagerService(Android5.1)深入分析(四)安装应用_android action_package_needs_verification

android action_package_needs_verification

一、安装的Activity

在Android,通过发送Intent可以启动应用的安装过程,如下所示:

  1. Uri uri = Uri.fromFile(new File(filename));
  2. Intent inent = new Intent(Intent.ACTION_VIEW);
  3. intent.SetDataAndType(uri, application/vnd.android.package-archive);
  4. startActivity(intent);

在Android的系统应用PackageInstaller中有一个PackageInstallActivity会响应这个Intent。在这个Activity中有两个重要的成员变量mPm和mInstaller,分别是ApplicationPackageManger和PackageInstaller的实例对象,这两个对象也是PackageManagerService和PackageInstallerService在应用中的代理对象。

PackageInstallerAcivity中创建这两个对象的代码如下:

  1. protected void onCreate(Bundler icicle) {
  2. super.onCreate(icicle);
  3. mPm = getPackageManager();
  4. mInstaller = mPm.getPackageInstaller();
  5. ......
  6. }


二、管理安装会话

PackageManagerInstallerService是Android5.0新加入的服务,主要用于管理安装会话(Installer session)。在Android5.0中,可以通过PackageManagerInstallerService来分配一个SessionId,这个系统唯一的ID代表一次安装过程,如果一个应用的安装分成几个阶段来完成,即使设备重启了,也可以通过这个ID来继续安装过程。

PackageManagerInstallerService中提供的接口createSession来创建一个Session:

  1. @Override
  2. public int createSession(SessionParams params, String installerPackageName, int userId) {
  3. try {
  4. return createSessionInternal(params, installerPackageName, userId);
  5. } catch (IOException e) {
  6. throw ExceptionUtils.wrap(e);
  7. }
  8. }

这个方法返回一个系统唯一值作为SessionID,如果希望再次使用这个Session,可以通过接口openSession方法来打开它,代码如下:

  1. @Override
  2. public IPackageInstallerSession openSession(int sessionId) {
  3. try {
  4. return openSessionInternal(sessionId);
  5. } catch (IOException e) {
  6. throw ExceptionUtils.wrap(e);
  7. }
  8. }

openSession返回一个IPackageInstallerSession对象,它是Binder服务PackageInstallerSession的IBinder对象。每个Install Session都会在SystemServer中有一个对应的PackageInstallerSession对象。在PackageInstallerService中mSessions数组保存了所有PackageInstallerSession对象,定义如下:

private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();

当系统启动时,PackageManageService初始化时会创建PackageManagerInstallerService服务,在这个服务的初始化函数中,会读取/data/system目录下的install_sessions.xml文件,这个文件保存系统未完成的Install Session。然后PackagemanagerInstallerService会根据文件的内容创建PackageInstallerSession对象并插入mSessions中。

PackageInstallerSession中保存了应用安装相关的数据。例如,安装包路径,安装进度、中间数据保存的目录等。


三、应用安装过程

应用可以调用PackageManager的installPackage方法来开始安装过程,最终会调用到PackageManagerService的installPackage或者installPackageAsUser来执行安装过程,整个安装过程比较复杂。

整个安装过程可以分成两个阶段:

1.第一阶段把需要安装的应用复制到/data/app目录下

2.第二阶段是对apk文件扫描优化,装载到内存中。


3.1 复制文件

PackageManagerService的installPackage方法只是用当前用户安装应用,最后也会调用installPackageAsUser

  1. @Override
  2. public void installPackage(String originPath, IPackageInstallObserver2 observer,
  3. int installFlags, String installerPackageName, VerificationParams verificationParams,
  4. String packageAbiOverride) {
  5. installPackageAsUser(originPath, observer, installFlags, installerPackageName, verificationParams,
  6. packageAbiOverride, UserHandle.getCallingUserId());
  7. }

下面我们就来看看installPackageAsUser方法:

  1. @Override
  2. public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
  3. int installFlags, String installerPackageName, VerificationParams verificationParams,
  4. String packageAbiOverride, int userId) {
  5. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);//检查调用进程的权限
  6. //检查调用进程的永华是否有权限安装应用
  7. final int callingUid = Binder.getCallingUid();
  8. enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser");
  9. //检查指定的用户是否被限制安装应用
  10. if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
  11. try {
  12. if (observer != null) {
  13. observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);
  14. }
  15. } catch (RemoteException re) {
  16. }
  17. return;
  18. }
  19. if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
  20. installFlags |= PackageManager.INSTALL_FROM_ADB;
  21. } else {
  22. // Caller holds INSTALL_PACKAGES permission, so we're less strict
  23. // about installerPackageName.
  24. installFlags &= ~PackageManager.INSTALL_FROM_ADB;
  25. installFlags &= ~PackageManager.INSTALL_ALL_USERS;
  26. }
  27. UserHandle user;
  28. if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {//给所有用户安装
  29. user = UserHandle.ALL;
  30. } else {
  31. user = new UserHandle(userId);
  32. }
  33. verificationParams.setInstallerUid(callingUid);
  34. final File originFile = new File(originPath);
  35. final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
  36. final Message msg = mHandler.obtainMessage(INIT_COPY);
  37. msg.obj = new InstallParams(origin, observer, installFlags,//保存参数到InstallParamsm,发送消息
  38. installerPackageName, verificationParams, user, packageAbiOverride);
  39. mHandler.sendMessage(msg);
  40. }

installPackageAsUser先检查调用进程是否有安装应用的权限,再检查调用进程所属的用户是否有权限安装应用,最后检查指定的用户是否被限制安装应用。如果参数installFlags带有INSTALL_ALL_USERS,则该应用将给系统中所有用户安装,否则只给指定用户安装。
安装应用实践比较长,因此不可能在一个函数中完成。上面函数把数据保存在installParams然后发送了INIT_COPY消息。

下面我们再来看看消息处理:

  1. void doHandleMessage(Message msg) {
  2. switch (msg.what) {
  3. case INIT_COPY: {
  4. HandlerParams params = (HandlerParams) msg.obj;
  5. int idx = mPendingInstalls.size();
  6. if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
  7. // If a bind was already initiated we dont really
  8. // need to do anything. The pending install
  9. // will be processed later on.
  10. if (!mBound) {
  11. // If this is the only one pending we might
  12. // have to bind to the service again.
  13. if (!connectToService()) {//绑定DefaultContainerService
  14. Slog.e(TAG, "Failed to bind to media container service");
  15. params.serviceError();
  16. return;
  17. } else {//连接成功把安装信息保存到mPendingInstalls
  18. // Once we bind to the service, the first
  19. // pending request will be processed.
  20. mPendingInstalls.add(idx, params);
  21. }
  22. } else {//如果已经绑定好了
  23. mPendingInstalls.add(idx, params);
  24. // Already bound to the service. Just make
  25. // sure we trigger off processing the first request.
  26. if (idx == 0) {
  27. mHandler.sendEmptyMessage(MCS_BOUND);
  28. }
  29. }
  30. break;
  31. }

INIT_COPY消息的处理将绑定DefaultContainerService,因为这是一个异步的过程,要等待绑定的结果通过onServiceConnected返回,所以这里的安装参数放到了mPendingInstalls列表中。如果这个Service以前就绑定好了,现在就不需要再绑定,安装信息也会先放到mPendingInstalls。如果有多个安装请求同时到达,这里通过mPendingInstalls列表对他们进行排队。如果列表中只有一项,说明没有更多的安装请求,因此这种情况下回立即发出MCS_BOUND消息。而onServiceConnected方法同样是发出MCS_BOUND消息:

  1. class DefaultContainerConnection implements ServiceConnection {
  2. public void onServiceConnected(ComponentName name, IBinder service) {
  3. if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
  4. IMediaContainerService imcs =
  5. IMediaContainerService.Stub.asInterface(service);
  6. mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
  7. }
  8. public void onServiceDisconnected(ComponentName name) {
  9. if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");
  10. }
  11. };

看下MCS_BOUND的消息处理

  1. case MCS_BOUND: {
  2. if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
  3. if (msg.obj != null) {
  4. mContainerService = (IMediaContainerService) msg.obj;
  5. }
  6. if (mContainerService == null) {//没有连接成功
  7. // Something seriously wrong. Bail out
  8. Slog.e(TAG, "Cannot bind to media container service");
  9. for (HandlerParams params : mPendingInstalls) {
  10. // Indicate service bind error
  11. params.serviceError();//通知出错了
  12. }
  13. mPendingInstalls.clear();
  14. } else if (mPendingInstalls.size() > 0) {
  15. HandlerParams params = mPendingInstalls.get(0);
  16. if (params != null) {
  17. if (params.startCopy()) {//执行安装
  18. // We are done... look for more work or to
  19. // go idle.
  20. if (DEBUG_SD_INSTALL) Log.i(TAG,
  21. "Checking for more work or unbind...");
  22. // Delete pending install
  23. if (mPendingInstalls.size() > 0) {
  24. mPendingInstalls.remove(0);//工作完成,删除第一项
  25. }
  26. if (mPendingInstalls.size() == 0) {//如果没有安装消息了,延时发送10秒MCS_UNBIND消息
  27. if (mBound) {
  28. if (DEBUG_SD_INSTALL) Log.i(TAG,
  29. "Posting delayed MCS_UNBIND");
  30. removeMessages(MCS_UNBIND);
  31. Message ubmsg = obtainMessage(MCS_UNBIND);
  32. // Unbind after a little delay, to avoid
  33. // continual thrashing.
  34. sendMessageDelayed(ubmsg, 10000);
  35. }
  36. } else {
  37. // There are more pending requests in queue.
  38. // Just post MCS_BOUND message to trigger processing
  39. // of next pending install.
  40. if (DEBUG_SD_INSTALL) Log.i(TAG,
  41. "Posting MCS_BOUND for next work");
  42. mHandler.sendEmptyMessage(MCS_BOUND);//还有消息继续发送MCS_BOUND消息
  43. }
  44. }
  45. }
  46. } else {
  47. // Should never happen ideally.
  48. Slog.w(TAG, "Empty queue");
  49. }
  50. break;
  51. }

如果结束了我们看看MCS_UNBIND消息的处理

  1. case MCS_UNBIND: {
  2. // If there is no actual work left, then time to unbind.
  3. if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind");
  4. if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {
  5. if (mBound) {
  6. if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()");
  7. disconnectService();//断开连接
  8. }
  9. } else if (mPendingInstalls.size() > 0) {
  10. // There are more pending requests in queue.
  11. // Just post MCS_BOUND message to trigger processing
  12. // of next pending install.
  13. mHandler.sendEmptyMessage(MCS_BOUND);
  14. }
  15. break;
  16. }

MCS_UNBIND消息的处理,如果处理的时候发现mPendingInstalls又有数据了,还是发送MCS_BOUND消息继续安装,否则断开和DefaultContainerService的连接,安装结束。
下面我们看执行安装的函数startCopy:

  1. final boolean startCopy() {
  2. boolean res;
  3. try {
  4. if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
  5. if (++mRetries > MAX_RETRIES) {//重试超过4次退出
  6. Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
  7. mHandler.sendEmptyMessage(MCS_GIVE_UP);
  8. handleServiceError();
  9. return false;
  10. } else {
  11. handleStartCopy();
  12. res = true;
  13. }
  14. } catch (RemoteException e) {
  15. if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
  16. mHandler.sendEmptyMessage(MCS_RECONNECT);//安装出错,发送重新连接
  17. res = false;
  18. }
  19. handleReturnCode();
  20. return res;
  21. }

handleStartCopy和copyApk代码就不分析了。

handleStartCopy函数先通过DefaultContainerService调用了getMinimallPackageInfo来确定安装位置是否有足够的空间,并在PackageInfoLite对象的recommendedIntallLocation记录错误原因。发现空间不够,会调用installer的freecache方法来释放一部分空间。

再接下来handleStartCopy有很长一段都在处理apk的校验,这个校验过程是通过发送Intent ACTION_PACKAGE_NEEDS_VERIFICATION给系统中所有接受该Intent的应用来完成。如果无需校验,直接调用InstallArgs对象的copyApk方法。

而copyApk方法同样是调用DefaultContainerService的copyPackage将应用的文件复制到/data/app下,如果还有native动态库,也会把包在apk文件中的动态库提取出来。

执行完copyApk后,应用安装到了data/app目录下了。


3.2 装载应用

接下来是第二阶段的工作,把应用的格式装换成oat格式,为应用创建数据目录。最后把应用信息装载进PackageManagerService的数据结构中。

接着上面startCopy方法最后会调用handleReturnCode方法,代码如下:

  1. @Override
  2. void handleReturnCode() {
  3. // If mArgs is null, then MCS couldn't be reached. When it
  4. // reconnects, it will try again to install. At that point, this
  5. // will succeed.
  6. if (mArgs != null) {
  7. processPendingInstall(mArgs, mRet);
  8. }
  9. }

我们继续看下processPendingInstall函数。

  1. private void processPendingInstall(final InstallArgs args, final int currentStatus) {
  2. // Queue up an async operation since the package installation may take a little while.
  3. mHandler.post(new Runnable() {
  4. public void run() {
  5. mHandler.removeCallbacks(this);//防止重复调用
  6. // Result object to be returned
  7. PackageInstalledInfo res = new PackageInstalledInfo();
  8. res.returnCode = currentStatus;
  9. res.uid = -1;
  10. res.pkg = null;
  11. res.removedInfo = new PackageRemovedInfo();
  12. if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {//如果安装成功了
  13. args.doPreInstall(res.returnCode);
  14. synchronized (mInstallLock) {
  15. installPackageLI(args, res);//装载安装的应用
  16. }
  17. args.doPostInstall(res.returnCode, res.uid);
  18. }
  19. ..........
  20. if (!doRestore) {
  21. // 发送POST_INSTALL消息
  22. Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
  23. mHandler.sendMessage(msg);
  24. }
  25. }
  26. });
  27. }

processPendingInstall方法post了一个消息,这样安装过程以异步的方式继续执行。在post消息的处理中,首先调用installPackageLI来装载应用,然后很大的代码在执行备份,备份是通过BackupManagerService来完成的。备份完成后,通过发送POST_INSTALL消息来继续处理。而这个消息的处理主要就是在发送广播,应用安装完成后要通知系统中其他的应用开始处理,比如Launcher中需要增加应用的图标等。

我们来分析下installPackageLI方法:

  1. private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
  2. final int installFlags = args.installFlags;
  3. String installerPackageName = args.installerPackageName;
  4. File tmpPackageFile = new File(args.getCodePath());
  5. boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
  6. boolean onSd = ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0);
  7. boolean replace = false;
  8. final int scanFlags = SCAN_NEW_INSTALL | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE;
  9. // Result object to be returned
  10. res.returnCode = PackageManager.INSTALL_SUCCEEDED;
  11. if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
  12. // Retrieve PackageSettings and parse package
  13. final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
  14. | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
  15. | (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
  16. PackageParser pp = new PackageParser();
  17. pp.setSeparateProcesses(mSeparateProcesses);
  18. pp.setDisplayMetrics(mMetrics);
  19. final PackageParser.Package pkg;
  20. try {
  21. pkg = pp.parsePackage(tmpPackageFile, parseFlags);//解析apk文件
  22. } catch (PackageParserException e) {
  23. res.setError("Failed parse during installPackageLI", e);
  24. return;
  25. }

这里先调用parsePackage解析apk文件,这个之前分析过,我们就不再分析了。

继续分析processPendingInstall函数

  1. if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {//如果安装的升级应用,继续使用以前的老的包名
  2. String oldName = mSettings.mRenamedPackages.get(pkgName);
  3. if (pkg.mOriginalPackages != null
  4. && pkg.mOriginalPackages.contains(oldName)
  5. && mPackages.containsKey(oldName)) {
  6. // This package is derived from an original package,
  7. // and this device has been updating from that original
  8. // name. We must continue using the original name, so
  9. // rename the new package here.
  10. pkg.setPackageName(oldName);//设置老的包名
  11. pkgName = pkg.packageName;
  12. replace = true;
  13. if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
  14. + oldName + " pkgName=" + pkgName);
  15. } else if (mPackages.containsKey(pkgName)) {
  16. // This package, under its official name, already exists
  17. // on the device; we should replace it.
  18. replace = true;
  19. if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
  20. }
  21. }

继续分析

  1. if (systemApp && onSd) {//不能将系统应用装载sd卡
  2. // Disable updates to system apps on sdcard
  3. res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
  4. "Cannot install updates to system apps on sdcard");
  5. return;
  6. }
  7. if (!args.doRename(res.returnCode, pkg, oldCodePath)) {//重命名出错
  8. res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
  9. return;
  10. }

继续分析

  1. if (replace) {//如果安装的是升级包,调用replacePackageLI
  2. replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
  3. installerPackageName, res);
  4. } else {//如果是新应用,调用installNewPackageLI继续处理
  5. installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
  6. args.user, installerPackageName, res);
  7. }
  8. synchronized (mPackages) {
  9. final PackageSetting ps = mSettings.mPackages.get(pkgName);
  10. if (ps != null) {
  11. res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
  12. }
  13. }

下面我们分析下installNewPackageLI函数

  1. private void installNewPackageLI(PackageParser.Package pkg,
  2. int parseFlags, int scanFlags, UserHandle user,
  3. String installerPackageName, PackageInstalledInfo res) {
  4. // Remember this for later, in case we need to rollback this install
  5. String pkgName = pkg.packageName;
  6. if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
  7. boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();
  8. synchronized(mPackages) {
  9. if (mSettings.mRenamedPackages.containsKey(pkgName)) {
  10. // A package with the same name is already installed, though
  11. // it has been renamed to an older name. The package we
  12. // are trying to install should be installed as an update to
  13. // the existing one, but that has not been requested, so bail.
  14. res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
  15. + " without first uninstalling package running as "
  16. + mSettings.mRenamedPackages.get(pkgName));
  17. return;
  18. }
  19. if (mPackages.containsKey(pkgName)) {
  20. // Don't allow installation over an existing package with the same name.
  21. res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
  22. + " without first uninstalling.");
  23. return;
  24. }
  25. }
  26. try {
  27. PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,//调用scanPackageLI
  28. System.currentTimeMillis(), user);
  29. updateSettingsLI(newPackage, installerPackageName, null, null, res);
  30. // delete the partially installed application. the data directory will have to be
  31. // restored if it was already existing
  32. if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
  33. // remove package from internal structures. Note that we want deletePackageX to
  34. // delete the package data and cache directories that it created in
  35. // scanPackageLocked, unless those directories existed before we even tried to
  36. // install.
  37. deletePackageLI(pkgName, UserHandle.ALL, false, null, null,
  38. dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,
  39. res.removedInfo, true);
  40. }
  41. } catch (PackageManagerException e) {
  42. res.setError("Package couldn't be installed in " + pkg.codePath, e);
  43. }
  44. }

这里和上篇博客分析扫描apk文件类似,我们来看下这个函数scanPackageLI

  1. private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,
  2. int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
  3. boolean success = false;
  4. try {
  5. final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags,
  6. currentTime, user);
  7. success = true;
  8. return res;
  9. } finally {
  10. if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
  11. removeDataDirsLI(pkg.packageName);
  12. }
  13. }
  14. }

scanPackageLI函数主要调用了scanPackageDirtyLI函数,这个函数前面分析过了就不分析了。


我们再来看下在processPendingInstall函数中调用完installPackageLI函数之后,发送了一个POST_INSTALL消息,我们来看下这个消息的处理

  1. case POST_INSTALL: {
  2. if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
  3. PostInstallData data = mRunningInstalls.get(msg.arg1);
  4. mRunningInstalls.delete(msg.arg1);
  5. boolean deleteOld = false;
  6. if (data != null) {
  7. InstallArgs args = data.args;
  8. PackageInstalledInfo res = data.res;
  9. if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {//安装成功
  10. final String packageName = res.pkg.applicationInfo.packageName;
  11. res.removedInfo.sendBroadcast(false, true, false);
  12. Bundle extras = new Bundle(1);
  13. extras.putInt(Intent.EXTRA_UID, res.uid);
  14. // Now that we successfully installed the package, grant runtime
  15. // permissions if requested before broadcasting the install.
  16. if ((args.installFlags
  17. & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0) {
  18. grantRequestedRuntimePermissions(res.pkg, args.user.getIdentifier(),
  19. args.installGrantPermissions);
  20. }
  21. // Determine the set of users who are adding this
  22. // package for the first time vs. those who are seeing
  23. // an update.
  24. int[] firstUsers;
  25. int[] updateUsers = new int[0];
  26. if (res.origUsers == null || res.origUsers.length == 0) {
  27. firstUsers = res.newUsers;
  28. } else {
  29. firstUsers = new int[0];
  30. for (int i=0; i<res.newUsers.length; i++) {
  31. int user = res.newUsers[i];
  32. boolean isNew = true;
  33. for (int j=0; j<res.origUsers.length; j++) {
  34. if (res.origUsers[j] == user) {
  35. isNew = false;
  36. break;
  37. }
  38. }
  39. if (isNew) {
  40. int[] newFirst = new int[firstUsers.length+1];
  41. System.arraycopy(firstUsers, 0, newFirst, 0,
  42. firstUsers.length);
  43. newFirst[firstUsers.length] = user;
  44. firstUsers = newFirst;
  45. } else {
  46. int[] newUpdate = new int[updateUsers.length+1];
  47. System.arraycopy(updateUsers, 0, newUpdate, 0,
  48. updateUsers.length);
  49. newUpdate[updateUsers.length] = user;
  50. updateUsers = newUpdate;
  51. }
  52. }
  53. }
  54. sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,//发送ACTION_PACKAGE_ADDED广播
  55. packageName, extras, null, null, firstUsers);
  56. final boolean update = res.removedInfo.removedPackage != null;
  57. if (update) {
  58. extras.putBoolean(Intent.EXTRA_REPLACING, true);
  59. }
  60. sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
  61. packageName, extras, null, null, updateUsers);
  62. if (update) {//如果是升级,发送更多广播
  63. sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
  64. packageName, extras, null, null, updateUsers);
  65. sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
  66. null, null, packageName, null, updateUsers);
  67. // treat asec-hosted packages like removable media on upgrade
  68. if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
  69. if (DEBUG_INSTALL) {
  70. Slog.i(TAG, "upgrading pkg " + res.pkg
  71. + " is ASEC-hosted -> AVAILABLE");
  72. }
  73. int[] uidArray = new int[] { res.pkg.applicationInfo.uid };
  74. ArrayList<String> pkgList = new ArrayList<String>(1);
  75. pkgList.add(packageName);
  76. sendResourcesChangedBroadcast(true, true,
  77. pkgList,uidArray, null);
  78. }
  79. }
  80. if (res.removedInfo.args != null) {
  81. // Remove the replaced package's older resources safely now
  82. deleteOld = true;
  83. }
  84. // If this app is a browser and it's newly-installed for some
  85. // users, clear any default-browser state in those users
  86. if (firstUsers.length > 0) {
  87. // the app's nature doesn't depend on the user, so we can just
  88. // check its browser nature in any user and generalize.
  89. if (packageIsBrowser(packageName, firstUsers[0])) {
  90. synchronized (mPackages) {
  91. for (int userId : firstUsers) {
  92. mSettings.setDefaultBrowserPackageNameLPw(null, userId);
  93. }
  94. }
  95. }
  96. }
  97. // Log current value of "unknown sources" setting
  98. EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
  99. getUnknownSourcesSettings());
  100. }
  101. // Force a gc to clear up things
  102. Runtime.getRuntime().gc();
  103. // We delete after a gc for applications on sdcard.
  104. if (deleteOld) {
  105. synchronized (mInstallLock) {
  106. res.removedInfo.args.doPostDeleteLI(true);
  107. }
  108. }
  109. if (args.observer != null) {
  110. try {
  111. Bundle extras = extrasForInstallResult(res);
  112. args.observer.onPackageInstalled(res.name, res.returnCode,
  113. res.returnMsg, extras);
  114. } catch (RemoteException e) {
  115. Slog.i(TAG, "Observer no longer exists.");
  116. }
  117. }
  118. } else {
  119. Slog.e(TAG, "Bogus post-install token " + msg.arg1);
  120. }
  121. } break;

这样安装应用的流程就讲完了。



声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/199168?site
推荐阅读
相关标签
  

闽ICP备14008679号