安装应用的过程解析
    一.开机安装 
        PackageManagerService处理各种应用的安装,卸载,管理等工作,开机时由systemServer启动此服务
        (源文件路径:android\frameworks\base\services\Java\com\android\server\PackageManagerService.java)

        PackageManagerService服务启动的流程:
            1.首先扫描安装“system\framework”目录下的jar包
                mFrameworkInstallObserver = new AppDirObserver(mFrameworkDir.getPath(), OBSERVER_EVENTS, true);  
                mFrameworkInstallObserver.startWatching();  
                scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode | SCAN_NO_DEX, 0);
            
            2.扫描安装系统system/app的应用程序
                mSystemAppDir = new File(Environment.getRootDirectory(), "app");  
                mSystemInstallObserver = new AppDirObserver(mSystemAppDir.getPath(), OBSERVER_EVENTS, true);  
                mSystemInstallObserver.startWatching();  
                scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
            
            3.制造商的目录下/vendor/app应用包
                mVendorAppDir = new File("/vendor/app");  
                mVendorInstallObserver = new AppDirObserver(mVendorAppDir.getPath(), OBSERVER_EVENTS, true);  
                mVendorInstallObserver.startWatching();  
                scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
            
            4.扫描“data\app”目录,即用户安装的第三方应用
                scanDirLI(mAppInstallDir, 0, scanMode, 0); 
            
            5.扫描" data\app-private"目录,即安装DRM保护的APK文件(一个受保护的歌曲或受保护的视频是使用 DRM 保护的文件)
                scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,scanMode, 0); 
        
        扫描方法的代码清单:
            private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {  
                String[] files = dir.list();  
                if (files == null) {  
                    Log.d(TAG, "No files in app dir " + dir);  
                    return;  
                }  
                if (false) {  
                    Log.d(TAG, "Scanning app dir " + dir);  
                }  
                int i;  
                for (i=0; i                     File file = new File(dir, files[i]);  
                    if (!isPackageFilename(files[i])) {  
                        continue;  
                    }  
                    PackageParser.Package pkg = scanPackageLI(file,flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);
                    if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 && mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {  
                        Slog.w(TAG, "Cleaning up failed install of " + file);  
                        file.delete();  
                    }  
                }  
            }
            并且从该扫描方法中可以看出调用了scanPackageLI(),跟踪scanPackageLI()方法后发现,程序经过很多次的if else 的筛选,最后判定可以安装后调用了 mInstaller.install()方法
                //private PackageParser.Package scanPackageLI(File scanFile,int parseFlags, int scanMode, long currentTime)
                if (mInstaller != null) {  
                    int ret = mInstaller.install(pkgName, useEncryptedFSDir,  pkg.applicationInfo.uid,pkg.applicationInfo.uid);  
                    if(ret < 0) {  
                        mLastScanError =PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;  
                        return null;  
                    }  
                }
            mInstaller.install()通过LocalSocketAddress address = new LocalSocketAddress("installd", LocalSocketAddress.Namespace.RESERVED)来指挥installd在C语言的文件中完成工作
            PackageManagerService
                1)从apk, xml中载入pacakge信息, 存储到内部成员变量中, 用于后面的查找. 关键的方法是scanPackageLI().
                2)各种查询操作, 包括query Intent操作.
                3)install package和delete package的操作. 还有后面的关键方法是installPackageLI().
                
            安装应用的过程:  
                1.scanDirLI(Filedir, int flags, int scanMode) //遍历安装指定目录下的文件  
                2.scanPackageLI(FilescanFile,File destCodeFile, FiledestResourceFile, int parseFlags,int scanMode);//安装package文件  
                3.scanPackageLI( File scanFile, File destCodeFile, FiledestResourceFile,PackageParser.Package pkg, intparseFlags, int scanMode) ;//通过解析安装包parsePackage获取到安装包的信息结构  
                4.mInstaller.install(pkgName,pkg.applicationInfo.uid, pkg.applicationInfo.uid);//实现文件复制的安装过程,源文件路径frameworks\base\cmds\installd\installd.install  

            
    二、从网络上下载应用:
        下载完成后,会自动调用Packagemanager的安装方法installPackage(),PackageManagerService类的installPackage()函数为安装程序入口
            //final Uri packageURI:文件下载完成后保存的路径  
            //final IPackageInstallObserver observer:处理返回的安装结果  
            //final int flags:安装的参数,从market上下载的应用,安装参数为-r (replace)
            //final String installerPackageName:安装完成后此名称保存在settings里一般为null,不是关键参数  
            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()方法
            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 (!mBound) {    
                            if (!connectToService()) {  
                                Slog.e(TAG, "Failed to bind to media container service");  
                                params.serviceError();  
                                return;  
                            } else {  
                                mPendingInstalls.add(idx, params);  
                            }  
                        } else {  
                            mPendingInstalls.add(idx, params);   
                            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) {  
                            Slog.e(TAG, "Cannot bind to media container service");  
                            for (HandlerParams params : mPendingInstalls) {  
                                mPendingInstalls.remove(0);  
                                params.serviceError();  
                            }  
                            mPendingInstalls.clear();  
                        } else if (mPendingInstalls.size() > 0) {  
                            HandlerParams params = mPendingInstalls.get(0);  
                            if (params != null) {  
                                params.startCopy();  
                            }  
                        } else {  
                            Slog.w(TAG, "Empty queue");  
                        }  
                        break;  
                    }  
                    /****************省略若干**********************/  
                }  
            } 
        
        然后调用抽象类HandlerParams中的一个startCopy()方法 
            abstract class HandlerParams {

                final void startCopy() {
                    /***************若干if语句判定否这打回handler消息*******/
                    handleReturnCode();
                }
            }
        
        handleReturnCode()复写了两次其中有一次是删除时要调用的,只列出安装调用的一个方法
            @Override  
            void handleReturnCode() {
               if (mArgs != null) {  
                   processPendingInstall(mArgs, mRet);  
               }  
            } 
        
        这时可以清楚的看见 processPendingInstall()被调用,其中run()方法如下
            run(){  
            synchronized (mInstallLock) {  
                    /************省略*****************/  
                    installPackageLI(args, true, 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;  
            } 

        installPackageLI()的具体实现
            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);  
                res.returnCode = PackageManager.INSTALL_SUCCEEDED;  
                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;  
                } 
                pp = null;  
                String oldCodePath = null;  
                boolean systemApp = false;  
                synchronized (mPackages) {  
                    if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0) {  
                        String oldName = mSettings.mRenamedPackages.get(pkgName);  
                        if (pkg.mOriginalPackages != null  && pkg.mOriginalPackages.contains(oldName) && mPackages.containsKey(oldName)) {  
                            pkg.setPackageName(oldName);  
                            pkgName = pkg.packageName;  
                            replace = true;  
                        } else if (mPackages.containsKey(pkgName)) {  
                              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) {   
                    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;  
                }  
                setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());  
                pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();  
                if (replace) { 
                    //带有参数INSTALL_REPLACE_EXISTING
                    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());  
                /***********************省略若干**************************************************/    
            }  
            
    三、从ADB工具安装
        其入口函数源文件为pm.java(源文件路径:android\frameworks\base\cmds\pm\src\com\android\commands\pm\pm.java),
        其中\system\framework\pm.jar 包管理库,包管理脚本 \system\bin\pm 解析
        
        其中showUsage就是adb使用方法
            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")) {  
                        installFlags |= PackageManager.INSTALL_EXTERNAL;  
                    } else if (opt.equals("-f")) {  
                        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 调用的是
        public void installPackage( final Uri packageURI, final IPackageInstallObserver observer, final int flags,final String installerPackageName) 
    
    四、从SD卡安装
        把APK安装包保存在SD卡中,从手机里访问SD卡中的APK安装包,点击就可以启动安装界面系统应用Packageinstaller.apk处理这种方式下的安装及卸载界面流程  
        PackageInstallerActivity负责解析包,判断是否是可用的Apk文件,创建临时安装文件/data/data/com.android.packageinstaller/files/ApiDemos.apk ,
        并启动安装确认界面startInstallConfirm,列出解析得到的该应用基本信息。如果手机上已安装有同名应用,则需要用户确认是否要替换安装,确认安装后,
        启动InstallAppProgress调用安装接口完成安装。
        系统调用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跳转到InstallAppProgress类
            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();  
                }
            }
        
        在onCreate()方法中调用了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);  
               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);  
            }  
    
    其它:  
        1. PackageManagerService.java的内部类AppDirObserver实现了监听app目录的功能,当
            把某个APK拖到app目录下时可以直接调用scanPackageLI完成安装。  
        2.手机数据区目录“data/system/packages.xml”文件中包含了手机上所有已安装应用的
            基本信息,如安装路径、申请的permission等信息。  
 
 

更多相关文章

  1. 一款常用的 Squid 日志分析工具
  2. GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
  3. RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
  4. Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
  5. Android(安卓)studio xml 无提示解决办法
  6. Android上进程闪退,读取Manifest.xml配置文件出错
  7. android 关于localhost和访问本机服务的方法
  8. 如何把公司要求的一些文件预到android 用户空间系统空间
  9. 设置Button监听最典型的2种方法

随机推荐

  1. 新浪微博布局学习——活用Android的Relat
  2. android Pull方式解析xml文件
  3. Android拖动控件改变其位置
  4. Android中内容提供者ContentProvider实现
  5. android Http文件上传
  6. 【Android】手机地图功能——利用手机GPS
  7. android 6.0/7.1/9 默认打开 开发者选项
  8. android 自定义组合控件并实现点击事件
  9. android 使用http协议上传文件
  10. Android实现点击缩略图放大效果