Android PackageManagerService

PMS中須要預先加載應用相關的組件、庫以及資源文件。bash

PMS提供的全部功能中,最核心的當屬應用安裝服務。做爲一個普通的用戶,最多見的場景是經過應用商店,或者本身手動從網絡下載apk,在文件管理器中手動安裝應用。做爲一個開發者,最經常使用的是AS的Run按鈕,本質上最終會使用腳本調用adb install服務來實現應用的安裝。微信

全部的安裝場景實際上是異曲同工,最終調用到了PMS的scanPackageDirtyLI來實現安裝功能,而所謂的安裝,實際上是對apk文件的解析、加載。網絡

Android 應用安裝場景總結

安裝流程

1. 系統應用安裝

開機時PMS的啓動流程和其它系統Service的流程是同樣的:從init進程被拉起,再到zygote進程,再到SystemServer進程,進入到SystemServer.main方法後,開始初始化包含PMS在內的各大系統Servicesession

SystemServer.run()app

// system_server 進程的入口函數
public static void main(String[] args) {
	// 注意這個run方法只是個普通的run函數,和線程自動調用的run並無聯繫
    new SystemServer().run();
}
private void run() {
	...
    try {
        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
        // 在這裏啓動PMS服務
        startBootstrapServices();
        startCoreServices();
        startOtherServices();
        SystemServerInitThreadPool.shutdown();
    } catch (Throwable ex) {
        Slog.e("System", "******************************************");
        Slog.e("System", "************ Failure starting system services", ex);
        throw ex;
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    }
    ...
}
private void startBootstrapServices() {
	 ...
	 // 經過調用PMS的靜態main方法來初始化並返回實例
	 // 注意這裏的main方法和SystemServer這種的main方法仍是不一樣的,並非由反射進行調用的
    mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
        mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
   ...
}
複製代碼

PMS.main()異步

public static PackageManagerService main(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
    ...
    // 包相關的處理操做將在PMS構造器中完成,整個流程很長
    PackageManagerService m = new PackageManagerService(context, installer,
            factoryTest, onlyCore);
    ...
    // 在ServiceManager進行註冊
    ServiceManager.addService("package", m);
    return m;
}

public PackageManagerService(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
     ...
     // 收集 priv-app 目錄下apk信息
     final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
     scanDirTracedLI(privilegedAppDir, mDefParseFlags
                | PackageParser.PARSE_IS_SYSTEM
                | PackageParser.PARSE_IS_SYSTEM_DIR
                | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
     
     // 收集 app 目錄下apk信息
     final File systemAppDir = new File(Environment.getRootDirectory(), "app");
     scanDirTracedLI(systemAppDir, mDefParseFlags
            | PackageParser.PARSE_IS_SYSTEM
            | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
            
     // 收集 /vendor/app 目錄下apk信息
     File vendorAppDir = new File("/vendor/app");
     try {
         vendorAppDir = vendorAppDir.getCanonicalFile();
     } catch (IOException e) {
         // failed to look up canonical path, continue with original one
     }
     scanDirTracedLI(vendorAppDir, mDefParseFlags
            | PackageParser.PARSE_IS_SYSTEM
            | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);  
     ...
}

private void scanDirTracedLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir");
    try {
        scanDirLI(dir, parseFlags, scanFlags, currentTime);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}
    
private void scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
     final MultiTaskDealer dealer = (iMultitaskNum > 1) ? MultiTaskDealer.startDealer(
            MultiTaskDealer.PACKAGEMANAGER_SCANER, iMultitaskNum) : null;
            
     // 初始化一個掃描任務
     Runnable scanTask = new Runnable() {
            public void run() {
                try {
                    scanPackageTracedLI(ref_file, ref_parseFlags | 
                    	PackageParser.PARSE_MUST_BE_APK, ref_scanFlags, ref_currentTime, null);
                } catch (PackageManagerException e) {
                    ...
                }
            }
        };
        
    // 將任務放置到線程池中進行處理
    if (dealer != null)
        dealer.addTask(scanTask);
    else
        scanTask.run();
}

private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
        int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
    try {
        return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}
// 掃描apk文件方法
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
        long currentTime, UserHandle user) throws PackageManagerException {
 	 ...
 	 final PackageParser.Package pkg;
    try {
        pkg = pp.parsePackage(scanFile, parseFlags);
    } catch (PackageParserException e) {
        throw PackageManagerException.from(e);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
    
    ...
    return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);       
}
複製代碼

Package.parsePacakge()async

public Package parsePackage(File packageFile, int flags) throws PackageParserException {
    if (packageFile.isDirectory()) {
        return parseClusterPackage(packageFile, flags);
    } else {
        return parseMonolithicPackage(packageFile, flags);
    }
}
    
private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
	 ...
	 // 該方法將會解析Manifest.xml文件,將apk組件信息進行保存
	 final Package pkg = parseBaseApk(baseApk, assets, flags);
	 ...
}
    
private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
        String[] outError) throws XmlPullParserException, IOException {
    ...
    return parseBaseApkCommon(pkg, null, res, parser, flags, outError);    
}
    
// 該方法爲組件解析的核心方法,由於篇幅較長不詳細分析了,無非就是解析xml文件提取出組件信息,封裝成Package返回
private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
        XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
        IOException {
 	 ...       
}
複製代碼
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile,
                                            final int policyFlags, int scanFlags, long currentTime, UserHandle user)
        throws PackageManagerException {
    ...
    // 將應用組件信息提取出來後,調用Internel方法進行應用安裝
    PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, scanFile, policyFlags,
            scanFlags, currentTime, user);
    ...
    return scannedPkg;
}
private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg, File scanFile,
                                                    int policyFlags, int scanFlags, long currentTime, UserHandle user)
        throws PackageManagerException {
    ...
    // Note that we invoke the following method only if we are about to unpack an application
    PackageParser.Package scannedPkg = scanPackageLI(pkg, policyFlags, scanFlags
            | SCAN_UPDATE_SIGNATURE, currentTime, user);
    ...        
    
}
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, final int policyFlags,
                                            int scanFlags, long currentTime, UserHandle user) throws 		PackageManagerException {
    boolean success = false;
    try {
    	 // 最終調用到了核心安裝方法
        final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags,
                currentTime, user);
        success = true;
        return res;
    } finally {
        ...
    }
}
複製代碼

2. 經過安裝器安裝

PackageInstallerActivity.startInstall()ide

private void startInstall() {
    // Start subactivity to actually install the application
    Intent newIntent = new Intent();
    newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
            mPkgInfo.applicationInfo);
    newIntent.setData(mPackageURI);
    if(!TextUtils.isEmpty(mInstallFromPkgName)){
        newIntent.putExtra(InstallAppProgress.EXTRA_INSTALL_SOURCE,mInstallFromPkgName);
    }
    newIntent.putExtra(InstallAppProgress.EXTRA_NEWINSTALL,mNewInstall);
    newIntent.putExtra(AdDataHelper.INTENT_EXTRA_PI_ID, mPid);
    newIntent.setClass(this, InstallAppProgress.class);
    String installerPackageName = getIntent().getStringExtra(
            Intent.EXTRA_INSTALLER_PACKAGE_NAME);
	 ...
	 // 經過啓動Activity到InstallAppProgress進行PMS調用
    startActivity(newIntent);
    finish();
}
複製代碼

InstallAppProgress.startInstall()函數

private void startInstall() {
    ...
    // 異步進行安裝
    mInstallHandler.post(new Runnable() {
        @Override
        public void run() {
            doPackageStage(pm, params);
        }
    });
}
private void doPackageStage(PackageManager pm, PackageInstaller.SessionParams params) {
    final PackageInstaller packageInstaller = pm.getPackageInstaller();
    PackageInstaller.Session session = null;
    try {
        ...
        Intent broadcastIntent = new Intent(BROADCAST_ACTION + mInstallId);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(
                InstallAppProgress.this /*context*/,
                sessionId,
                broadcastIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        // binder call 到PacakgeInstallerSession進行處理
        session.commit(pendingIntent.getIntentSender());
        mInstallStartTime = SystemClock.elapsedRealtime();
    } catch (IOException e) {
        ...
    } finally {
        IoUtils.closeQuietly(session);
    }
}
複製代碼

PackageInstallerSesson.commit()post

@Override
public void commit(IntentSender statusReceiver) {
    ...
    final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
            statusReceiver, sessionId, mIsInstallerDeviceOwner, userId);
    // 由於在server端,此時仍爲binder線程在處理,post個message異步進行處理
    mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
}
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        ...
        synchronized (mLock) {
            ...
            try {
                commitLocked();
            } catch (PackageManagerException e) {
                ...
            }
            return true;
        }
    }
};

private void commitLocked() throws PackageManagerException {
	...
	// 最終調用pm.installStage方法進行安裝
    mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
                installerPackageName, installerUid, user, mCertificates);
}
複製代碼

PMS.installStage()

void installStage(String packageName, File stagedDir, String stagedCid,
                  IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
                  String installerPackageName, int installerUid, UserHandle user,
                  Certificate[][] certificates) {
    ...
    // 異步進行文件拷貝
    final Message msg = mHandler.obtainMessage(INIT_COPY);
    ...
    mHandler.sendMessage(msg);
}

void doHandleMessage(Message msg) {
    switch (msg.what) {
        case INIT_COPY: {
            HandlerParams params = (HandlerParams) msg.obj;
            if (!mBound) {
                ...
            } else {
                mPendingInstalls.add(idx, params);
                if (idx == 0) {
                    mHandler.sendEmptyMessage(MCS_BOUND);
                }
            }
            break;
        }
   ...
   		  case MCS_BOUND: {
            ...
            if (mContainerService == null) {
                ...
            } else if (mPendingInstalls.size() > 0) {
                HandlerParams params = mPendingInstalls.get(0);
                if (params != null) {
                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                            System.identityHashCode(params));
                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                    // 開始拷貝apk文件
                    if (params.startCopy()) {
                       ...
                    }
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
            } 
            break;
}

final boolean startCopy() {
    ...
     try {
        if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
        if (++mRetries > MAX_RETRIES) {
            ...
        } else {
        	  // 拷貝文件
            handleStartCopy();
            res = true;
        }
    } catch (RemoteException e) {
        if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
        mHandler.sendEmptyMessage(MCS_RECONNECT);
        res = false;
    }
    // 拷貝完成後進入安裝階段
    handleReturnCode();
    return res;
}

@Override
void handleReturnCode() {
    if (mArgs != null) {
        processPendingInstall(mArgs, mRet);
    }
}

private void processPendingInstall(final InstallArgs args, final int currentStatus) {
    mHandler.post(new Runnable() {
        public void run() {
            mHandler.removeCallbacks(this);
            PackageInstalledInfo res = new PackageInstalledInfo();
            res.setReturnCode(currentStatus);
            res.uid = -1;
            res.pkg = null;
            res.removedInfo = null;
            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                args.doPreInstall(res.returnCode);
                synchronized (mInstallLock) {
                	   // 進行安裝操做
                    installPackageTracedLI(args, res);
                }
                args.doPostInstall(res.returnCode, res.uid);
            }
            ...
        }
    }
}
private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
    try {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
        installPackageLI(args, res);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
    try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
                "installPackageLI")) {
        if (replace) {
        	  // 應用升級或降級
            replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
                    installerPackageName, res);
        } else {
        	  // 應用從未被安裝
            installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
                    args.user, installerPackageName, volumeUuid, res);
        }
    }
}
private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,
                                  int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,
                                  PackageInstalledInfo res) {
    ...
    try {
     	 // 最終調用到了scanPackageTracedLI方法,和系統啓動的掃描場景異曲同工
        PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags,
                System.currentTimeMillis(), user);
        ...
    } catch (PackageManagerException e) {
        res.setError("Package couldn't be installed in " + pkg.codePath, e);
    }
    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
複製代碼

3. 經過adb install安裝

當前在命令行輸入adb install xxx.apk文件後,最終會調用到framework的PM.main()方法,進行相關處理

ublic static void main(String[] args) {
    int exitCode = 1;
    try {
        exitCode = new Pm().run(args);
    } catch (Exception e) {
        ...
    }
    System.exit(exitCode);
}
public int run(String[] args) throws RemoteException {
	...
	if ("install".equals(op)) {
        return runInstall();
   }
   ...
}
    
private int runInstall() throws RemoteException {
    final InstallParams params = makeInstallParams();
    
    // 獲取 session 服務鏈接
    final int sessionId = doCreateSession(params.sessionParams,
            params.installerPackageName, params.userId);
    try {
        ...
        if (doCommitSession(sessionId, false /*logSuccess*/)
                != PackageInstaller.STATUS_SUCCESS) {
            return 1;
        }
        System.out.println("Success");
        return 0;
    } finally {
        ...
    }
}

private int doCommitSession(int sessionId, boolean logSuccess) throws RemoteException {
    PackageInstaller.Session session = null;
    try {
        session = new PackageInstaller.Session(
                mInstaller.openSession(sessionId));
        final LocalIntentReceiver receiver = new LocalIntentReceiver();
        // 經過binder call到PackageInstallerSession來實現安裝,和安裝器場景一致
        session.commit(receiver.getIntentSender());
        ...
    } finally {
        IoUtils.closeQuietly(session);
    }
}
複製代碼

4. 應用商店自動安裝

以豌豆莢爲表明的應用商店是可否不須要用戶自動點擊安裝按鈕來實現自動安裝的

這裏的核心實現思路是使用到了AcessibilityService的功能

Android 提供AcessibilityService服務的初衷是但願將其運用給視力、聽力欠缺人羣,可是國內開發者使用它作了不少」黑科技」,表明做如微信自動搶紅包。

核心安裝方法: PMS.scanPackageDirtyLI()

private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,
                                                     final int policyFlags, final int scanFlags, long currentTime, UserHandle user)
            throws PackageManagerException {
	 ...
	 // 將保存在Package中的解析信息取出,存入PMS,自此安裝基本成功,AMS能夠查詢到組件信息並調用
	 int N = pkg.providers.size();
    StringBuilder r = null;
    int i;
    for (i = 0; i < N; i++) {
        PackageParser.Provider p = pkg.providers.get(i);
        p.info.processName = fixProcessName(pkg.applicationInfo.processName,
                p.info.processName, pkg.applicationInfo.uid);
        // 將provider信息放入PMS
        mProviders.addProvider(p);
        ...
    }
    if (r != null) {
        if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Providers: " + r);
    }
    N = pkg.services.size();
    r = null;
    for (i = 0; i < N; i++) {
        PackageParser.Service s = pkg.services.get(i);
        s.info.processName = fixProcessName(pkg.applicationInfo.processName,
                s.info.processName, pkg.applicationInfo.uid);
        // 將service信息放入PMS
        mServices.addService(s);
        ...
    }
    if (r != null) {
        if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Services: " + r);
    }
    N = pkg.receivers.size();
    r = null;
    for (i = 0; i < N; i++) {
        PackageParser.Activity a = pkg.receivers.get(i);
        a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                a.info.processName, pkg.applicationInfo.uid);
        // 將receiver信息放入PMS
        mReceivers.addActivity(a, "receiver");
        ...
    }
    if (r != null) {
        if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Receivers: " + r);
    }
    N = pkg.activities.size();
    r = null;
    for (i = 0; i < N; i++) {
        PackageParser.Activity a = pkg.activities.get(i);
        a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                a.info.processName, pkg.applicationInfo.uid);
        // 將activity信息放入PMS
        mActivities.addActivity(a, "activity");
        ...
    }
   	... 
}
複製代碼

總結

  • /system/priv-app, /system/priv-app, /vendor/app/ 下的應用在系統啓動時掃描並安裝
  • adb install 與使用應用安裝器安裝,本質上都使用到了PackageInstallerSession的服務進行安裝
  • 國內應用商店如豌豆莢,經常使用AcessibilityService來實現自動安裝功能
相關文章
相關標籤/搜索