• 安卓高手之路之PackageManagerservice(二)


    adb install 流程 - new_abc的专栏 - 博客频道 - CSDN.NET

    应用安装涉及目录:        

    system/app ---------------系统自带的应用程序,获得adb root权限才能删除

    data/app  ---------------用户程序安装的目录。安装时把 apk文件复制到此目录

    data/data ---------------存放应用程序的数据

    data/dalvik-cache--------将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,其大小约为原始apk文件大小的四分之一)

    安装过程:

    复制APK安装包到data/app目录下,解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录,并data/data目录下创建对应的应用数据目录。

    卸载过程:

    删除安装过程中在上述三个目录下创建的文件及目录

    带着这些知识去看安装过程,可能会更容易理解引起。

    当我们利用adb安装一个软件包时,到底流程是怎么样的呢,这里主要介绍一个安装包在目标机中的安装过程。

    adb install 也是用的pm命令去安装的,所以开始是在pm.java中。

    我们看下流程:

    1、调用pm程序开始安装

    得用Pm安装时,一般是shell运行一个pm命令,并传送相应的参数,我们通过adb连接到机器,输入pm,会打出pm的一些参数

    # pm

    pm

    usage: pm [list|path|install|uninstall]

           pm list packages [-f] [-d] [-e] [-u] [FILTER]

           pm list permission-groups

           pm list permissions [-g] [-f] [-d] [-u] [GROUP]

           pm list instrumentation [-f] [TARGET-PACKAGE]

           pm list features

           pm list libraries

           pm path PACKAGE

           pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-

           pm uninstall [-k] PACKAGE

           pm clear PACKAGE

           pm enable PACKAGE_OR_COMPONENT

           pm disable PACKAGE_OR_COMPONENT

           pm setInstallLocation [0/auto] [1/internal] [2/external]

    当我们安装一个软件包时,shell运行pm程序并传入pm install ***等参数,我们看下pm.java

    1. public static void main(String[] args) {  
    2.         new Pm().run(args);  
    3.     }  
    public static void main(String[] args) {
            new Pm().run(args);
        }

    这里运行pm的run方法

    1. public void run(String[] args) {  
    2.       .  
    3.       .  
    4.       if ("install".equals(op)) {  
    5.             runInstall();  
    6.             return;  
    7.         }  
    8. }  
    public void run(String[] args) {
          .
          .
          if ("install".equals(op)) {
                runInstall();
                return;
            }
    }
    



    匹配到install时,运行runInstall

    runInstall主要对其它参数进行解析,最后调用:

    1. try {  
    2.             mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,  
    3.                     installerPackageName);  
    4.   
    5.             synchronized (obs) {  
    6.                 while (!obs.finished) {  
    7.                     try {  
    8.                         obs.wait();  
    9.                     } catch (InterruptedException e) {  
    10.                     }  
    11.                 }  
    12.                 if (obs.result == PackageManager.INSTALL_SUCCEEDED) {  
    13.                     System.out.println("Success");  
    14.                 } else {  
    15.                     System.err.println("Failure ["  
    16.                             + installFailureToString(obs.result)  
    17.                             + "]");  
    18.                 }  
    19.             }  
    20.         } catch (RemoteException e) {  
    21.             System.err.println(e.toString());  
    22.             System.err.println(PM_NOT_RUNNING_ERR);  
    23.         }  
    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);
            }

    2、PackageManagerService安装前处理

    这里调用了PackageManager的installPackage接口,并最终调用PackageManagerService的installPackage进行具体的安装工作

    在installPackage中,主要发送一条INIT_COPY消息到PackageHandler,PackageHandler处理这条消息最后调用doHandleMessage,这中间的过程就不说了,对于INIT_COPY消息 ,首先调用connectToService,连接服务DefaultContainerService

    在连接成功的时候触发DefaultContainerConnection的onServiceConnected,这里面又往PackageHandler发了一条MCS_BOUND。这里面触发startCopy

    1. final void startCopy() {  
    2.             try {  
    3.                 if (DEBUG_SD_INSTALL) Log.i(TAG, "startCopy");  
    4.                 retry++;  
    5.                 if (retry > MAX_RETRIES) {  
    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;  
    10.                 } else {  
    11.                     handleStartCopy();  
    12.                     if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_UNBIND");  
    13.                     mHandler.sendEmptyMessage(MCS_UNBIND);  
    14.                 }  
    15.             } catch (RemoteException e) {  
    16.                 if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_RECONNECT");  
    17.                 mHandler.sendEmptyMessage(MCS_RECONNECT);  
    18.             }  
    19.             handleReturnCode();  
    20. }  
    final void startCopy() {
                try {
                    if (DEBUG_SD_INSTALL) Log.i(TAG, "startCopy");
                    retry++;
                    if (retry > MAX_RETRIES) {
                        Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
                        mHandler.sendEmptyMessage(MCS_GIVE_UP);
                        handleServiceError();
                        return;
                    } else {
                        handleStartCopy();
                        if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_UNBIND");
                        mHandler.sendEmptyMessage(MCS_UNBIND);
                    }
                } catch (RemoteException e) {
                    if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_RECONNECT");
                    mHandler.sendEmptyMessage(MCS_RECONNECT);
                }
                handleReturnCode();
    }



    handleStartCopy进行一些安装前准备工作,最后调用handleReturnCode

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

    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, true, res);  
    16.                 }  
    17.                 args.doPostInstall(res.returnCode);  
    18.             }  
    19.   
    20.             // A restore should be performed at this point if (a) the install  
    21.             // succeeded, (b) the operation is not an update, and (c) the new  
    22.             // package has a backupAgent defined.  
    23.             final boolean update = res.removedInfo.removedPackage != null;  
    24.             boolean doRestore = (!update  
    25.                     && res.pkg != null  
    26.                     && res.pkg.applicationInfo.backupAgentName != null);  
    27.   
    28.             // Set up the post-install work request bookkeeping.  This will be used  
    29.             // and cleaned up by the post-install event handling regardless of whether  
    30.             // there's a restore pass performed.  Token values are >= 1.  
    31.             int token;  
    32.             if (mNextInstallToken < 0) mNextInstallToken = 1;  
    33.             token = mNextInstallToken++;  
    34.   
    35.             PostInstallData data = new PostInstallData(args, res);  
    36.             mRunningInstalls.put(token, data);  
    37.             if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);  
    38.   
    39.             if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {  
    40.                 // Pass responsibility to the Backup Manager.  It will perform a  
    41.                 // restore if appropriate, then pass responsibility back to the  
    42.                 // Package Manager to run the post-install observer callbacks  
    43.                 // and broadcasts.  
    44.                 IBackupManager bm = IBackupManager.Stub.asInterface(  
    45.                         ServiceManager.getService(Context.BACKUP_SERVICE));  
    46.                 if (bm != null) {  
    47.                     if (DEBUG_INSTALL) Log.v(TAG, "token " + token  
    48.                             + " to BM for possible restore");  
    49.                     try {  
    50.                         bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);  
    51.                     } catch (RemoteException e) {  
    52.                         // can't happen; the backup manager is local  
    53.                     } catch (Exception e) {  
    54.                         Slog.e(TAG, "Exception trying to enqueue restore", e);  
    55.                         doRestore = false;  
    56.                     }  
    57.                 } else {  
    58.                     Slog.e(TAG, "Backup Manager not found!");  
    59.                     doRestore = false;  
    60.                 }  
    61.             }  
    62.   
    63.             if (!doRestore) {  
    64.                 // No restore possible, or the Backup Manager was mysteriously not  
    65.                 // available -- just fire the post-install work request directly.  
    66.                 if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);  
    67.                 Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);  
    68.                 mHandler.sendMessage(msg);  
    69.             }  
    70.         }  
    71.     });  
    72. }  
        private void processPendingInstall(final InstallArgs args, final int currentStatus) {
            // Queue up an async operation since the package installation may take a little while.
            mHandler.post(new Runnable() {
                public void run() {
                    mHandler.removeCallbacks(this);
                     // Result object to be returned
                    PackageInstalledInfo res = new PackageInstalledInfo();
                    res.returnCode = currentStatus;
                    res.uid = -1;
                    res.pkg = null;
                    res.removedInfo = new PackageRemovedInfo();
                    if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                        args.doPreInstall(res.returnCode);
                        synchronized (mInstallLock) {
                            installPackageLI(args, true, res);
                        }
                        args.doPostInstall(res.returnCode);
                    }
    
                    // A restore should be performed at this point if (a) the install
                    // succeeded, (b) the operation is not an update, and (c) the new
                    // package has a backupAgent defined.
                    final boolean update = res.removedInfo.removedPackage != null;
                    boolean doRestore = (!update
                            && res.pkg != null
                            && res.pkg.applicationInfo.backupAgentName != null);
    
                    // Set up the post-install work request bookkeeping.  This will be used
                    // and cleaned up by the post-install event handling regardless of whether
                    // there's a restore pass performed.  Token values are >= 1.
                    int token;
                    if (mNextInstallToken < 0) mNextInstallToken = 1;
                    token = mNextInstallToken++;
    
                    PostInstallData data = new PostInstallData(args, res);
                    mRunningInstalls.put(token, data);
                    if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
    
                    if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
                        // Pass responsibility to the Backup Manager.  It will perform a
                        // restore if appropriate, then pass responsibility back to the
                        // Package Manager to run the post-install observer callbacks
                        // and broadcasts.
                        IBackupManager bm = IBackupManager.Stub.asInterface(
                                ServiceManager.getService(Context.BACKUP_SERVICE));
                        if (bm != null) {
                            if (DEBUG_INSTALL) Log.v(TAG, "token " + token
                                    + " to BM for possible restore");
                            try {
                                bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
                            } catch (RemoteException e) {
                                // can't happen; the backup manager is local
                            } catch (Exception e) {
                                Slog.e(TAG, "Exception trying to enqueue restore", e);
                                doRestore = false;
                            }
                        } else {
                            Slog.e(TAG, "Backup Manager not found!");
                            doRestore = false;
                        }
                    }
    
                    if (!doRestore) {
                        // No restore possible, or the Backup Manager was mysteriously not
                        // available -- just fire the post-install work request directly.
                        if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
                        Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
                        mHandler.sendMessage(msg);
                    }
                }
            });
        }
    

    这里New了一个消息,把它的callback设置为这里new出来的Runnable,这里重载了run方法,最后会通过Handle,Looper,Message机制调用到这个run方法中进行。

    这里主要是调用了installPackageLI函数进行安装

    3、解析apk

    在installPackageLI中,会new 一个PackageParser对package进行解析,调用parsePackage函数 parsePackage(File sourceFile, String destCodePath,

                DisplayMetrics metrics, int flags)函数根据参数进行一些处理后最终调用parsePackage(

            Resources res, XmlResourceParser parser, int flags, String[] outError)对包进行解析,我们看到这个函数里面主要对配置文件AndroidManifest.xml文件进行了解析。我们会看到如下类似的代码

    1.     private Package parsePackage(  
    2.         Resources res, XmlResourceParser parser, int flags, String[] outError)  
    3.         throws XmlPullParserException, IOException {  
    4.    .  
    5.    .  
    6.     int outerDepth = parser.getDepth();  
    7.         while ((type=parser.next()) != parser.END_DOCUMENT  
    8.                && (type != parser.END_TAG || parser.getDepth() > outerDepth)) {  
    9.             if (type == parser.END_TAG || type == parser.TEXT) {  
    10.                 continue;  
    11.             }  
    12.   
    13.             String tagName = parser.getName();  
    14.             if (tagName.equals("application")) {  
    15.                 if (foundApp) {  
    16.                     if (RIGID_PARSER) {  
    17.                         outError[0] = "<manifest> has more than one <application>";  
    18.                         mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;  
    19.                         return null;  
    20.                     } else {  
    21.                         Log.w(TAG, "<manifest> has more than one <application>");  
    22.                         XmlUtils.skipCurrentTag(parser);  
    23.                         continue;  
    24.                     }  
    25.                 }  
    26.    .  
    27.    .  
    28. }  
        private Package parsePackage(
            Resources res, XmlResourceParser parser, int flags, String[] outError)
            throws XmlPullParserException, IOException {
       .
       .
        int outerDepth = parser.getDepth();
            while ((type=parser.next()) != parser.END_DOCUMENT
                   && (type != parser.END_TAG || parser.getDepth() > outerDepth)) {
                if (type == parser.END_TAG || type == parser.TEXT) {
                    continue;
                }
    
                String tagName = parser.getName();
                if (tagName.equals("application")) {
                    if (foundApp) {
                        if (RIGID_PARSER) {
                            outError[0] = "<manifest> has more than one <application>";
                            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                            return null;
                        } else {
                            Log.w(TAG, "<manifest> has more than one <application>");
                            XmlUtils.skipCurrentTag(parser);
                            continue;
                        }
                    }
       .
       .
    }

    4、安装包

    解析完之后 ,调用installNewPackageLI进行包的安装

    这里主要调用了scanPackageLI,对包进行安装,及保存package、provider、service、receiver和activity等信息保存在PackageManagerService服务中,我们会看到有如下代码

    1.  private PackageParser.Package scanPackageLI(PackageParser.Package pkg,  
    2.             int parseFlags, int scanMode, long currentTime) {  
    3.                                 // And now re-install the app.  
    4.                                 ret = mInstaller.install(pkgName, useEncryptedFSDir, pkg.applicationInfo.uid,  
    5.                                         pkg.applicationInfo.uid);  
    6.                                  
    7.    .  
    8.      
    9.     // Add the new setting to mSettings  
    10.             mSettings.insertPackageSettingLP(pkgSetting, pkg);  
    11.             // Add the new setting to mPackages  
    12.             mPackages.put(pkg.applicationInfo.packageName, pkg);  
    13.             // Make sure we don't accidentally delete its data.  
    14.             mSettings.mPackagesToBeCleaned.remove(pkgName);  
    15. }  
     private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
                int parseFlags, int scanMode, long currentTime) {
                                    // And now re-install the app.
                                    ret = mInstaller.install(pkgName, useEncryptedFSDir, pkg.applicationInfo.uid,
                                            pkg.applicationInfo.uid);
    
       .
    
        // Add the new setting to mSettings
                mSettings.insertPackageSettingLP(pkgSetting, pkg);
                // Add the new setting to mPackages
                mPackages.put(pkg.applicationInfo.packageName, pkg);
                // Make sure we don't accidentally delete its data.
                mSettings.mPackagesToBeCleaned.remove(pkgName);
    }



    这里的install最终会通过socket通信调用到installd.c中的do_install,其实也就是创建了一些目录而已。

  • 相关阅读:
    sql server 报表允许用windows 身份登录的任何人进入
    缩小sql server 日志文件
    IIS Internal Server Error &IIS8中部署WCF服务出错:HTTP 错误 404.3
    less 学习
    访问Index function 两次
    欢迎访问我的个人网站!
    我的web小游戏【持续更新中】
    排序算法(C#)
    存储过程详解
    C#集合
  • 原文地址:https://www.cnblogs.com/seven1979/p/4369617.html
Copyright © 2020-2023  润新知