为了账号安全,请及时绑定邮箱和手机立即绑定

Android应用程序安装过程解析(源码角度)(下篇)

标签:
Java Android

接着看下一篇+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

(2)从网络上下载应用:

下载完成后,会自动调用Packagemanager的安装方法installPackage()


public void installPackage(  
           final Uri packageURI, final IPackageInstallObserver observer, final int flags,  
           final String installerPackageName) {  
       mContext.enforceCallingOrSelfPermission(  
               android.Manifest.permission.INSTALL_PACKAGES, null);  
       Message msg = mHandler.obtainMessage(INIT_COPY);  
       msg.obj = new InstallParams(packageURI, observer, flags,  
               installerPackageName);  
       mHandler.sendMessage(msg);  
   }  

通过PackageHandler的实例mhandler.sendMessage(msg)把信息发给继承Handler的类HandleMessage()方法

class PackageHandler extends Handler{  

*****************省略若干********************  
         public void handleMessage(Message msg) {  
            try {  
                doHandleMessage(msg);  
            } finally {  
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
            }  
        }  
   ******************省略若干**********************  
 }  

把信息发给doHandleMessage()方法,方法中用switch()语句进行判定传来Message


 void doHandleMessage(Message msg) {  
            switch (msg.what) {  

                case INIT_COPY: {  
                    if (DEBUG_SD_INSTALL) Log.i(TAG, "init_copy");  
                    HandlerParams params = (HandlerParams) msg.obj;  
                    int idx = mPendingInstalls.size();  
                    if (DEBUG_SD_INSTALL) Log.i(TAG, "idx=" + idx);  
                    // If a bind was already initiated we dont really  
                    // need to do anything. The pending install  
                    // will be processed later on.  
                    if (!mBound) {  
                        // If this is the only one pending we might  
                        // have to bind to the service again.  
                        if (!connectToService()) {  
                            Slog.e(TAG, "Failed to bind to media container service");  
                            params.serviceError();  
                            return;  
                        } else {  
                            // Once we bind to the service, the first  
                            // pending request will be processed.  
                            mPendingInstalls.add(idx, params);  
                        }  
                    } else {  
                        mPendingInstalls.add(idx, params);  
                        // Already bound to the service. Just make  
                        // sure we trigger off processing the first request.  
                        if (idx == 0) {  
                            mHandler.sendEmptyMessage(MCS_BOUND);  
                        }  
                    }  
                    break;  
                }  
                case MCS_BOUND: {  
                    if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_bound");  
                    if (msg.obj != null) {  
                        mContainerService = (IMediaContainerService) msg.obj;  
                    }  
                    if (mContainerService == null) {  
                        // Something seriously wrong. Bail out  
                        Slog.e(TAG, "Cannot bind to media container service");  
                        for (HandlerParams params : mPendingInstalls) {  
                            mPendingInstalls.remove(0);  
                            // Indicate service bind error  
                            params.serviceError();  
                        }  
                        mPendingInstalls.clear();  
                    } else if (mPendingInstalls.size() > 0) {  
                        HandlerParams params = mPendingInstalls.get(0);  
                        if (params != null) {  
                            params.startCopy();  
                        }  
                    } else {  
                        // Should never happen ideally.  
                        Slog.w(TAG, "Empty queue");  
                    }  
                    break;  
                }  
            ****************省略若干**********************  
}  
}  

public final boolean sendMessage (Message msg)

public final boolean sendEmptyMessage (int what)

两者参数有别。

然后调用抽象类HandlerParams中的一个startCopy()方法

abstract class HandlerParams {

final void startCopy() {

*****若干if语句判定否这打回handler消息*

handleReturnCode();

}
}

handleReturnCode()复写了两次其中有一次是删除时要调用的,只列出安装调用的一个方法


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

这时可以清楚的看见 processPendingInstall()被调用。

其中run()方法如下


run(){  
synchronized (mInstallLock) {  
                        ************省略*****************  
                        installPackageLI(args, true, res);  

 }  
}  

instaPacakgeLI()args,res参数分析


//InstallArgs 是在PackageService定义的static abstract class InstallArgs 静态抽象类。


static abstract class InstallArgs {  
*********************************************************************  
其中定义了flag标志,packageURL,创建文件,拷贝apk,修改包名称,  
                    还有一些删除文件的清理,释放存储函数。  
    *********************************************************************  
}  
  class PackageInstalledInfo {  
        String name;  
        int uid;  
        PackageParser.Package pkg;  
        int returnCode;  
        PackageRemovedInfo removedInfo;  
 }  

-----------------------------------------------------------------------------------------

[java] view plain copy
private void installPackageLI(InstallArgs args,  
          boolean newInstall, PackageInstalledInfo res) {  
      int pFlags = args.flags;  
      String installerPackageName = args.installerPackageName;  
      File tmpPackageFile = new File(args.getCodePath());  
      boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);  
      boolean onSd = ((pFlags & PackageManager.INSTALL_EXTERNAL) != 0);  
      boolean replace = false;  
      int scanMode = (onSd ? 0 : SCAN_MONITOR) | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE  
              | (newInstall ? SCAN_NEW_INSTALL : 0);  
      // Result object to be returned  
      res.returnCode = PackageManager.INSTALL_SUCCEEDED;  
      // Retrieve PackageSettings and parse package  
      int parseFlags = PackageParser.PARSE_CHATTY |  
      (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) |  
      (onSd ? PackageParser.PARSE_ON_SDCARD : 0);  
      parseFlags |= mDefParseFlags;  
      PackageParser pp = new PackageParser(tmpPackageFile.getPath());  
      pp.setSeparateProcesses(mSeparateProcesses);  
      final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,  
              null, mMetrics, parseFlags);  
      if (pkg == null) {  
          res.returnCode = pp.getParseError();  
          return;  
      }  
      String pkgName = res.name = pkg.packageName;  
      if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {  
          if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {  
              res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;  
              return;  
          }  
      }  
      if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {  
          res.returnCode = pp.getParseError();  
          return;  
      }  
      // Get rid of all references to package scan path via parser.  
      pp = null;  
      String oldCodePath = null;  
      boolean systemApp = false;  
      synchronized (mPackages) {  
          // Check if installing already existing package  
          if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0) {  
              String oldName = mSettings.mRenamedPackages.get(pkgName);  
              if (pkg.mOriginalPackages != null  
                      && pkg.mOriginalPackages.contains(oldName)  
                      && mPackages.containsKey(oldName)) {  
                  // This package is derived from an original package,  
                  // and this device has been updating from that original  
                  // name.  We must continue using the original name, so  
                  // rename the new package here.  
                  pkg.setPackageName(oldName);  
                  pkgName = pkg.packageName;  
                  replace = true;  
              } else if (mPackages.containsKey(pkgName)) {  
                  // This package, under its official name, already exists  
                  // on the device; we should replace it.  
                  replace = true;  
              }  
          }  
          PackageSetting ps = mSettings.mPackages.get(pkgName);  
          if (ps != null) {  
              oldCodePath = mSettings.mPackages.get(pkgName).codePathString;  
              if (ps.pkg != null && ps.pkg.applicationInfo != null) {  
                  systemApp = (ps.pkg.applicationInfo.flags &  
                          ApplicationInfo.FLAG_SYSTEM) != 0;  
              }  
          }  
      }  
      if (systemApp && onSd) {  
          // Disable updates to system apps on sdcard  
          Slog.w(TAG, "Cannot install updates to system apps on sdcard");  
          res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;  
          return;  
      }  
      if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {  
          res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;  
          return;  
      }  
      // Set application objects path explicitly after the rename  
      setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());  
      pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();  
      if (replace) {  
          replacePackageLI(pkg, parseFlags, scanMode,  
                  installerPackageName, res);  
      } else {  
          installNewPackageLI(pkg, parseFlags, scanMode,  
                  installerPackageName,res);  
      }  
  }  

最后判断如果以前不存在那么调用installNewPackageLI()


private void installNewPackageLI(PackageParser.Package pkg,  
            int parseFlags,int scanMode,  
            String installerPackageName, PackageInstalledInfo res) {  
     ***********************省略若干*************************************************  
        PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,  
               System.currentTimeMillis());  
     ***********************省略若干**************************************************    
}  

最后终于回到了和开机安装一样的地方.与开机方式安装调用统一方法。

(3)从ADB工具安装

其入口函数源文件为pm.java

(源文件路径:android\frameworks\base\cmds\pm\src\com\android\commands\pm\pm.java)

其中\system\framework\pm.jar 包管理库

包管理脚本 \system\bin\pm 解析

showUsage就是使用方法


private static void showUsage() {   
        System.err.println("usage: pm [list|path|install|uninstall]");   
        System.err.println("       pm list packages [-f]");   
        System.err.println("       pm list permission-groups");   
        System.err.println("       pm list permissions [-g] [-f] [-d] [-u] [GROUP]");   
        System.err.println("       pm list instrumentation [-f] [TARGET-PACKAGE]");   
        System.err.println("       pm list features");   
        System.err.println("       pm path PACKAGE");   
        System.err.println("       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH");   
        System.err.println("       pm uninstall [-k] PACKAGE");   
        System.err.println("       pm enable PACKAGE_OR_COMPONENT");   
        System.err.println("       pm disable PACKAGE_OR_COMPONENT");   
        System.err.println("       pm setInstallLocation [0/auto] [1/internal] [2/external]");  
      **********************省略**************************  
   }  

安装时候会调用 runInstall()方法


private void runInstall() {  
      int installFlags = 0;  
      String installerPackageName = null;  
      String opt;  
      while ((opt=nextOption()) != null) {  
          if (opt.equals("-l")) {  
              installFlags |= PackageManager.INSTALL_FORWARD_LOCK;  
          } else if (opt.equals("-r")) {  
              installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;  
          } else if (opt.equals("-i")) {  
              installerPackageName = nextOptionData();  
              if (installerPackageName == null) {  
                  System.err.println("Error: no value specified for -i");  
                  showUsage();  
                  return;  
              }  
          } else if (opt.equals("-t")) {  
              installFlags |= PackageManager.INSTALL_ALLOW_TEST;  
          } else if (opt.equals("-s")) {  
              // Override if -s option is specified.  
              installFlags |= PackageManager.INSTALL_EXTERNAL;  
          } else if (opt.equals("-f")) {  
              // Override if -s option is specified.  
              installFlags |= PackageManager.INSTALL_INTERNAL;  
          } else {  
              System.err.println("Error: Unknown option: " + opt);  
              showUsage();  
              return;  
          }  
      }  
      String apkFilePath = nextArg();  
      System.err.println("\tpkg: " + apkFilePath);  
      if (apkFilePath == null) {  
          System.err.println("Error: no package specified");  
          showUsage();  
          return;  
      }  
      PackageInstallObserver obs = new PackageInstallObserver();  
      try {  
          mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,  
                  installerPackageName);  
          synchronized (obs) {  
              while (!obs.finished) {  
                  try {  
                      obs.wait();  
                  } catch (InterruptedException e) {  
                  }  
              }  
              if (obs.result == PackageManager.INSTALL_SUCCEEDED) {  
                  System.out.println("Success");  
              } else {  
                  System.err.println("Failure ["  
                          + installFailureToString(obs.result)  
                          + "]");  
              }  
          }  
      } catch (RemoteException e) {  
          System.err.println(e.toString());  
          System.err.println(PM_NOT_RUNNING_ERR);  
      }  
  }  

其中的


PackageInstallObserver obs = new PackageInstallObserver();

            mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,
                    installerPackageName);

如果安装成功

obs.result == PackageManager.INSTALL_SUCCEEDED)

又因为有

IPackageManage mPm;

    mPm = IpackageManager.Stub.asInterface(ServiceManager.getService("package"));

Stub是接口IPackageManage的静态抽象类,asInterface是返回IPackageManager代理的静态方法。

因为class PackageManagerService extends IPackageManager.Stub

所以mPm.installPackage 调用

/* Called when a downloaded package installation has been confirmed by the user */

public void installPackage(

        final Uri packageURI, final IPackageInstallObserver observer, final int flags,final String installerPackageName) 

这样就是从网络下载安装的入口了。

(4)从SD卡安装

系统调用PackageInstallerActivity.java(/home/zhongda/androidSRC/vortex-8inch-for-hoperun/packages/apps/PackageInstaller/src/com/android/packageinstaller)

进入这个Activity会判断信息是否有错,然后调用

  private void initiateInstall()判断是否曾经有过同名包的安装,或者包已经安装

通过后执行private void startInstallConfirm() 点击OK按钮后经过一系列的安装信息的判断Intent跳转到


public class InstallAppProgress extends Activity implements View.OnClickListener, OnCancelListener  
   public void onCreate(Bundle icicle) {  
        super.onCreate(icicle);  
        Intent intent = getIntent();  
        mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);  
        mPackageURI = intent.getData();  
        initView();  
    }  

方法中调用了initView()方法


public void initView() {  
       requestWindowFeature(Window.FEATURE_NO_TITLE);  
       setContentView(R.layout.op_progress);  
       int installFlags = 0;  
       PackageManager pm = getPackageManager();  
       try {  
           PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName,   
                   PackageManager.GET_UNINSTALLED_PACKAGES);  
           if(pi != null) {  
               installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;  
           }  
       } catch (NameNotFoundException e) {  
       }  
       if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) {  
           Log.w(TAG, "Replacing package:" + mAppInfo.packageName);  
       }  
       PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, mAppInfo,  
               mPackageURI);  
       mLabel = as.label;  
       PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);  
       mStatusTextView = (TextView)findViewById(R.id.center_text);  
       mStatusTextView.setText(R.string.installing);  
       mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);  
       mProgressBar.setIndeterminate(true);  
       // Hide button till progress is being displayed  
       mOkPanel = (View)findViewById(R.id.buttons_panel);  
       mDoneButton = (Button)findViewById(R.id.done_button);  
       mLaunchButton = (Button)findViewById(R.id.launch_button);  
       mOkPanel.setVisibility(View.INVISIBLE);  
       String installerPackageName = getIntent().getStringExtra(  
               Intent.EXTRA_INSTALLER_PACKAGE_NAME);  
       PackageInstallObserver observer = new PackageInstallObserver();  
       pm.installPackage(mPackageURI, observer, installFlags, installerPackageName);  
   }  

方法最后我们可以看到再次调用安装接口完成安装。

对于mSetting的介绍还不完善,后续会继续补充

本文是读过下面的几篇博客和Android系统源代码情景分析之后写成的,感谢各位作者。

参考:

http://ticktick.blog.51cto.com/823160/1669525
http://blog.csdn.net/hdhd588/article/details/6739281
http://blog.csdn.net/luoshengyang/article/details/6766010
《Android系统源代码情景分析》

点击查看更多内容
8人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消