APK安装过程详解

安装应用的过程解析
    一.开机安装 
        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<files.length; 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等信息。  
 
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值