adb install 流程

应用安装涉及目录:        
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

public static void main(String[] args) {
        new Pm().run(args);
    }
这里运行pm的run方法

public void run(String[] args) {
      .
      .
      if ("install".equals(op)) {
            runInstall();
            return;
        }
}

匹配到install时,运行runInstall

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

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

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

 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

    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文件进行了解析。我们会看到如下类似的代码

    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服务中,我们会看到有如下代码

 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,其实也就是创建了一些目录而已。






评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值