美文网首页
Android apk安装过程源码分析

Android apk安装过程源码分析

作者: 过期的薯条 | 来源:发表于2021-03-24 23:31 被阅读0次

    1.引言

    最近在面试复习,对android知识重新梳理了一遍,争取做到以点到面,把知识点都串起来。PackageManagerService 是android 核心服务之一。授权/app安装都与之相关。本文主要讲下安装apk的流程和扫描apk的过程。

    2.正题

    2.1 packageService 服务启动,apk扫描过程

    android中基本上每个cpp文件都对应一个名词一模一样的java文件,如surface.java 和surface.cpp ,Canves.java和Canves.cpp。包括本文的SystemServer.cpp和SystemServer.java。 往往c到java层的时候,都是调用java层的main方法。同理在系统初始化的时候,SystemServer.java的main方法会被调用.进而调用startBootstrapServices

    /services/java/com/android/server/SystemServer.java

     private void startBootstrapServices() {
            ....
           traceBeginAndSlog("StartPackageManagerService");
            try {
                Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
                mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
            } finally {
                Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
            }
        ....
    }
    

    /services/core/java/com/android/server/pm/PackageManagerService.java

       public static PackageManagerService main(Context context, Installer installer,
               boolean factoryTest, boolean onlyCore) {
           // Self-check for initial settings.
           PackageManagerServiceCompilerMapping.checkProperties();
    
           PackageManagerService m = new PackageManagerService(context, installer,
                   factoryTest, onlyCore);
           m.enableSystemUserPackages();
           ServiceManager.addService("package", m);
           final PackageManagerNative pmn = m.new PackageManagerNative();
           ServiceManager.addService("package_native", pmn);
           return m;
       }
    

    ServiceManager.addService("package", m);
    将每个服务保存到Map中,需要的时候就根据名词获取IBinder的引用。扫描系统app的核心就是在PackageManagerService的构造方法中。

    扫描特定目录下是否含有apk:

    scanDirTracedLI(frameworkDir, systemParseFlags,
                        systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0);
                if (!mPackages.containsKey("android")) {
                    throw new IllegalStateException(
                            "Failed to load frameworks package; check log for warnings");
                }
                for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
                    final SystemPartition partition = mDirsToScanAsSystem.get(i);
              
                //扫描priv-app目录
    
               if (partition.privAppFolder != null) {
                        scanDirTracedLI(partition.privAppFolder, systemParseFlags,
                                systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0);
                    }
                    scanDirTracedLI(partition.appFolder, systemParseFlags,
                            systemScanFlags | partition.scanFlag, 0);
                }
              ...
              //扫描system/app目录下的内容
              scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
    

    scanDirTracedLI方法调用的事scanDirLI方法,此方法是用了俩个for循环,第一for循环不断解析apk生成ParseResult,并且向 ArrayBlockingQueue中保存,下一个for循环就是不停的取出。

            for (File file : files) {
                    final boolean isPackage = (isApkFile(file) || file.isDirectory())
                            && !PackageInstallerService.isStageName(file.getName());
                    if (!isPackage) {
                        // Ignore entries which are not packages
                        continue;
                    }
                    parallelPackageParser.submit(file, parseFlags);
                    fileCount++;
                }
    
                // Process results one by one
                for (; fileCount > 0; fileCount--) {
                    ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
                    Throwable throwable = parseResult.throwable;
                    int errorCode = PackageManager.INSTALL_SUCCEEDED;
                    }
    
                    // Delete invalid userdata apps
                    if ((scanFlags & SCAN_AS_SYSTEM) == 0 &&
                            errorCode != PackageManager.INSTALL_SUCCEEDED) {
                        logCriticalInfo(Log.WARN,
                                "Deleting invalid package at " + parseResult.scanFile);
                        removeCodePathLI(parseResult.scanFile);
                    }
                }
            }
    

    services/core/java/com/android/server/pm/ParallelPackageParser.java

     /**
         * Submits the file for parsing
         * @param scanFile file to scan
         * @param parseFlags parse falgs
         */
        public void submit(File scanFile, int parseFlags) {
            mService.submit(() -> {
                ParseResult pr = new ParseResult();
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
                try {
                    PackageParser pp = new PackageParser();
                    pp.setSeparateProcesses(mSeparateProcesses);
                    pp.setOnlyCoreApps(mOnlyCore);
                    pp.setDisplayMetrics(mMetrics);
                    pp.setCacheDir(mCacheDir);
                    pp.setCallback(mPackageParserCallback);
                    pr.scanFile = scanFile;
                    pr.pkg = parsePackage(pp, scanFile, parseFlags);
                } catch (Throwable e) {
                    pr.throwable = e;
                } finally {
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
                try {
                    mQueue.put(pr);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    // Propagate result to callers of take().
                    // This is helpful to prevent main thread from getting stuck waiting on
                    // ParallelPackageParser to finish in case of interruption
                    mInterruptedInThread = Thread.currentThread().getName();
                }
            });
        }
    

    解析的操作放在parsePackage()方法中,生成一个PackageParser.Package对象。
    PackageParser类是真正执行解析apk的核心类,涉及到apk的解析操作。

    经过层层调用,最终解析方法是PackageParser .parseBaseApkCommon。此方法会对Minifest.xml进行解析。得到四大组件,以及各个权限。以下是部分代码

                String tagName = parser.getName();
                if (tagName.equals("activity")) {
                    Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
                            owner.baseHardwareAccelerated);
                    if (a == null) {
                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                        return false;
                    }
    
                    owner.activities.add(a);
                    parsedComponent = a.info;
    
                }
    

    Package 类的结构:

            public boolean baseHardwareAccelerated;
    
            // For now we only support one application per package.
            @UnsupportedAppUsage
            public ApplicationInfo applicationInfo = new ApplicationInfo();
    
            @UnsupportedAppUsage
            public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
            @UnsupportedAppUsage
            public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
            @UnsupportedAppUsage
            public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
            @UnsupportedAppUsage
            public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
            @UnsupportedAppUsage
            public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
            @UnsupportedAppUsage
            public final ArrayList<Service> services = new ArrayList<Service>(0);
            @UnsupportedAppUsage
            public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
    
            @UnsupportedAppUsage
            public final ArrayList<String> requestedPermissions = new ArrayList<String>();
    
            /** Permissions requested but not in the manifest. */
            public final ArrayList<String> implicitPermissions = new ArrayList<>();
    

    以上就是android 启动的时候 扫描app的过程。这个过程在安装apk的时候也会用到。


    2.2 apk安装过程

    分析安装过程先从应用层分析,入口在PackageInstallerActivity 这是系统默认的界面.点击ok之后,调用的事如下方法:

     mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install),
                    (ignored, ignored2) -> {
                        if (mOk.isEnabled()) {
                            if (mSessionId != -1) {
                                mInstaller.setPermissionsResult(mSessionId, true);
                                finish();
                            } else {
                                startInstall();
                            }
                        }
                    }, null);
            mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
                    (ignored, ignored2) -> {
                        // Cancel and finish
                        setResult(RESULT_CANCELED);
                        if (mSessionId != -1) {
                            mInstaller.setPermissionsResult(mSessionId, false);
                        }
                        finish();
                    }, null);
            setupAlert();
    

    mInstaller.setPermissionsResult(mSessionId, true); 调用的PackageInstallerService的setPermissionsResult

    @Override
        public void setPermissionsResult(int sessionId, boolean accepted) {
    
    //        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG);
            synchronized (mSessions) {
                PackageInstallerSession session = mSessions.get(sessionId);
                if (session != null) {
                    session.setPermissionsResult(accepted);
                }
            }
        }
    

    mContext.enforceCallingOrSelfPermission 是分析的入口方法.

    1.copy apk到data/app/

    session.setPermissionsResult会发送一个MSG_COMMIT的Message.最终调用到了PackageManagerService.installStage方法。installStage方法发送了一个INIT_COPY的Message,将apk拷贝到data/app/

    void doHandleMessage(Message msg) {
                switch (msg.what) {
                    case INIT_COPY: {
                        HandlerParams params = (HandlerParams) msg.obj;
                        if (params != null) {
                            if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                    System.identityHashCode(params));
                            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                            //开始copy,开始install
                            params.startCopy();
                            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                        }
                        break;
                    }
                    case SEND_PENDING_BROADCAST: {
    
    
    2.processPendingInstall

    processPendingInstall最终调用installPackagesLI方法。installPackagesLI是安装的核心。会继续调用prepareAppDataAfterInstallLIF方法

    1. 创建data/data用户数据:
    2. 将package信息写入到/data/system/package.xml
    private void prepareAppDataAfterInstallLIF(PackageParser.Package pkg) {
            final PackageSetting ps;
            synchronized (mPackages) {
                ps = mSettings.mPackages.get(pkg.packageName);
                mSettings.writeKernelMappingLPr(ps);
            }
    
            final UserManagerService um = sUserManager;
            UserManagerInternal umInternal = getUserManagerInternal();
            for (UserInfo user : um.getUsers(false /* excludeDying */)) {
                final int flags;
                if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
                    flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
                } else if (umInternal.isUserRunning(user.id)) {
                    flags = StorageManager.FLAG_STORAGE_DE;
                } else {
                    continue;
                }
    
                if (ps.getInstalled(user.id)) {
                    // TODO: when user data is locked, mark that we're still dirty
                    prepareAppDataLIF(pkg, user.id, flags);
                }
            }
        }
    

    相关文章

      网友评论

          本文标题:Android apk安装过程源码分析

          本文链接:https://www.haomeiwen.com/subject/nljkhltx.html