日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android PMS原理总结

發布時間:2023/12/20 Android 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android PMS原理总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一 system_server啟動PMS

Android的所有Java服務都是通過system_server進程啟動的,并且駐留在system_server進程中。SystemServer進程在啟動時,通過創建一個ServerThread線程啟動所有服務。

1.1 startBootstrapServices()

system_server的startBootstrapServices()函數會啟動一些引導服務,比如:

  • ActivityManagerService
  • PowerManagerService
  • DisplayManagerService
  • SensorService

其中PackageManagerService就在這里啟動。

private void startBootstrapServices() {//啟動installer服務Installer installer = mSystemServiceManager.startService(Installer.class);// We need the default display before we can initialize the package manager.mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);//處于加密狀態則僅僅解析核心應用// Only run "core" apps if we're encrypting the device.String cryptState = SystemProperties.get("vold.decrypt");if (ENCRYPTING_STATE.equals(cryptState)) {Slog.w(TAG, "Detected encryption in progress - only parsing core apps");mOnlyCore = true;} else if (ENCRYPTED_STATE.equals(cryptState)) {Slog.w(TAG, "Device encrypted - only parsing core apps");mOnlyCore = true;}// 創建PMS對象 - 啟動入口traceBeginAndSlog("StartPackageManagerService");mPackageManagerService = PackageManagerService.main(mSystemContext, installer,mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);// 是否首次啟動mFirstBoot = mPackageManagerService.isFirstBoot();// 獲取PackageManagermPackageManager = mSystemContext.getPackageManager();Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); }

1.2 startOtherService()

system_server的startOtherService()方法會啟動其他服務,在這里也會對PMS做一些處理

private void startOtherServices() {......if (!mOnlyCore) {........try {//將調用performDexOpt:Performs dexopt on the set of packagesmPackageManagerService.updatePackagesIfNeeded();}...............try {//執行Fstrim,執行磁盤維護操作//可能類似于TRIM技術,將標記為刪除的文件,徹底從硬盤上移除//而不是等到寫入時再移除,目的是提高寫入時效率mPackageManagerService.performFstrimIfNeeded();}................try {mPackageManagerService.systemReady();}...............} }

PMS啟動后將參與一些系統優化的工作,然后調用SystemReady方法通知系統服務進入就緒狀態

在system_server進程啟動過程,涉及PMS服務的主要幾個處理:

  • PMS.main()
  • PMS.performDexOpt()
  • PMS.systemReady()

二 PMS.main的入口

public static final PackageManagerService main(Context context, Installer installer,boolean factoryTest, boolean onlyCore) {PackageManagerService m = new PackageManagerService(context, installer,factoryTest, onlyCore);ServiceManager.addService("package", m);return m; }

在這個main入口中,直接實例化一個PMS服務,并將PMS服務放入ServiceManager中,便于管理,那么重點就是實例化PMS

代碼比較多,選擇一些重點

new PackageManagerService(context, installer, factoryTest, onlyCore);

public PackageManagerService(Context context, Installer installer,boolean factoryTest, boolean onlyCore) {EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis());if (mSdkVersion <= 0) {Slog.w(TAG, "**** ro.build.version.sdk not set!");}mContext = context;mFactoryTest = factoryTest;mOnlyCore = onlyCore;mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));// displayMetrics是一個描述界面顯示,尺寸,分辨率,密度的類mMetrics = new DisplayMetrics();// Settings是Android的全局管理者,用于協助PMS保存所有的安裝包信息mSettings = new Settings(context);mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);mSettings.addSharedUserLPw("android.uid.log", LOG_UID,ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);.......mInstaller = installer;// 獲取默認的顯示信息,保存到mMetricsgetDefaultDisplayMetrics(context, mMetrics);// 獲取系統配置信息SystemConfig systemConfig = SystemConfig.getInstance();mGlobalGids = systemConfig.getGlobalGids();mSystemPermissions = systemConfig.getSystemPermissions();mAvailableFeatures = systemConfig.getAvailableFeatures();synchronized (mInstallLock) {// writersynchronized (mPackages) {mHandlerThread = new ServiceThread(TAG,Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);mHandlerThread.start();mHandler = new PackageHandler(mHandlerThread.getLooper());Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);// 創建各種目錄,此時,到了我們熟悉的Android目錄了File dataDir = Environment.getDataDirectory();mAppDataDir = new File(dataDir, "data");mAppInstallDir = new File(dataDir, "app");mAppLib32InstallDir = new File(dataDir, "app-lib");mAsecInternalPath = new File(dataDir, "app-asec").getPath();mUserAppDataDir = new File(dataDir, "user");mDrmAppPrivateInstallDir = new File(dataDir, "app-private");// 創建用戶管理服務sUserManager = new UserManagerService(context, this,mInstallLock, mPackages);.......}....... }

此方法中,做了大概如下操作

  • 構造DisplayMetrics類:描述界面顯示,尺寸,分辨率,密度。構造完后并獲取默認的信息保存到變量mMetrics中
  • 構造Settings類:這個是Android的全局管理者,用于協助PMS保存所有的安裝包信息
  • 保存Installer對象
  • 獲取系統配置信息:SystemConfig構造函數中會通過readPermissions()解析指定目錄下的所有xml文件,然后把這些信息保存到systemConfig中,涉及的目錄有如下:
    • /system/etc/sysconfig
    • /system/etc/permissions
    • /oem/etc/sysconfig
    • /oem/etc/permissions
  • 創建data下的各種目錄,比如data/app, data/app-private等

其中我們最為熟悉的就是最后一點,創建各種Android目錄結構

各種第三方應用都是安裝在mAppInstallDir目錄中,直接搜索mAppInstallDir,得知在scanDirLI()函數中調用

掃描指定文件目錄下的apk文件

scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime)

private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {final File[] files = dir.listFiles();if (ArrayUtils.isEmpty(files)) {Log.d(TAG, "No files in app dir " + dir);return;}if (DEBUG_PACKAGE_SCANNING) {Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags+ " flags=0x" + Integer.toHexString(parseFlags));}for (File file : files) {final boolean isPackage = (isApkFile(file) || file.isDirectory())&& !PackageInstallerService.isStageName(file.getName());if (!isPackage) {// Ignore entries which are not packagescontinue;}try {scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,scanFlags, currentTime, null);} catch (PackageManagerException e) {Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());// Delete invalid userdata appsif ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);if (file.isDirectory()) {FileUtils.deleteContents(file);}file.delete();}}}}

掃描這個文件夾下面的所有文件,并且判斷是否為apk文件,如果不是繼續循環,如果是,則掃描這個路徑下的文件,調用scanPackageLI()

解析package信息,其中最重要的一個類為PackageParser,這個類和插件化技術處理聯系緊密

private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,long currentTime, UserHandle user) throws PackageManagerException {if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);parseFlags |= mDefParseFlags;PackageParser pp = new PackageParser();pp.setSeparateProcesses(mSeparateProcesses);pp.setOnlyCoreApps(mOnlyCore);pp.setDisplayMetrics(mMetrics);....... final PackageParser.Package pkg;try {// 1pkg = pp.parsePackage(scanFile, parseFlags);} catch (PackageParserException e) {throw PackageManagerException.from(e);} }

其中1位置使用PackageParser對象解析對應scanFile文件下的資源,最終返回一個pkg對象,pkg為PackageParser類中的內部類Package

Package:

public final static class Package {public String packageName;/** Names of any split APKs, ordered by parsed splitName */public String[] splitNames;// TODO: work towards making these paths invariant/*** Path where this package was found on disk. For monolithic packages* this is path to single base APK file; for cluster packages this is* path to the cluster directory.*/public String codePath;/** Path of base APK */public String baseCodePath;/** Paths of any split APKs, ordered by parsed splitName */public String[] splitCodePaths;/** Flags of any split APKs; ordered by parsed splitName */public int[] splitFlags;public boolean baseHardwareAccelerated;// For now we only support one application per package.public final ApplicationInfo applicationInfo = new ApplicationInfo();public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);public final ArrayList<Activity> activities = new ArrayList<Activity>(0);public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);public final ArrayList<Provider> providers = new ArrayList<Provider>(0);public final ArrayList<Service> services = new ArrayList<Service>(0);public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);....... ....... ....... }

其中有我們熟悉的activities,receivers,providers,services四大組件集合,Package對象就是包含了我們Android的所有資源信息

PackageParser中的parsePackage()方法--->parseMonolithicPackage()

public Package parsePackage(File packageFile, int flags) throws PackageParserException {if (packageFile.isDirectory()) {return parseClusterPackage(packageFile, flags);} else {return parseMonolithicPackage(packageFile, flags);}}@Deprecatedpublic Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {if (mOnlyCoreApps) {final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);if (!lite.coreApp) {throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,"Not a coreApp: " + apkFile);}}// 1final AssetManager assets = new AssetManager();try {final Package pkg = parseBaseApk(apkFile, assets, flags);pkg.codePath = apkFile.getAbsolutePath();return pkg;} finally {IoUtils.closeQuietly(assets);}}

在代碼中位置1 ,初始化一個AssetManager對象,并作為參數傳入parseBaseApk()函數,最終返回一個package對象

由此可見,parseBaseApk函數也是對這個apk文件的資源進行解析處理

注意:此時new出來的assetManager并不能直接加載apk資源,必須還要去調用addAssetPath方法

parseBaseApk():

private Package parseBaseApk(File apkFile, AssetManager assets, int flags)throws PackageParserException {final String apkPath = apkFile.getAbsolutePath();mParseError = PackageManager.INSTALL_SUCCEEDED;mArchiveSourcePath = apkFile.getAbsolutePath();if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);// 1 final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);Resources res = null;XmlResourceParser parser = null;try {res = new Resources(assets, mMetrics, null);assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,Build.VERSION.RESOURCES_SDK_INT);// 2 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);final String[] outError = new String[1];// 3final Package pkg = parseBaseApk(res, parser, flags, outError);if (pkg == null) {throw new PackageParserException(mParseError,apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);}pkg.baseCodePath = apkPath;pkg.mSignatures = null;return pkg;} catch (PackageParserException e) {throw e;} catch (Exception e) {throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,"Failed to read manifest from " + apkPath, e);} finally {IoUtils.closeQuietly(parser);}}

位置1代碼為

private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)throws PackageParserException {if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) {throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,"Invalid package file: " + apkPath);}// The AssetManager guarantees uniqueness for asset paths, so if this asset path// already exists in the AssetManager, addAssetPath will only return the cookie// assigned to it.int cookie = assets.addAssetPath(apkPath);if (cookie == 0) {throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,"Failed adding asset path: " + apkPath);}return cookie; }

此時,可以通過assetManager加載apk資源,包括res,androidMainfest.xml文件等

位置2 打開androidMainfest文件,也就是解析關鍵資源入口就找到了

位置3 將解析后的androidMainfest文件返回的parser對象傳入parseBaseApk函數

private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,String[] outError) throws XmlPullParserException, IOException {....... ....... while ((type = parser.next()) != XmlPullParser.END_DOCUMENT&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {if (type == XmlPullParser.END_TAG || type == XmlPullParser.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 {Slog.w(TAG, "<manifest> has more than one <application>");XmlUtils.skipCurrentTag(parser);continue;}}foundApp = true;//1if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) {return null;}}....... }....... }

在這個方法中,解析了AndroidMainfest中的application節點,這是我們需要關心的重點。

直接看位置1

private boolean parseBaseApplication(Package owner, Resources res,XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)throws XmlPullParserException, IOException {....... .......while ((type = parser.next()) != XmlPullParser.END_DOCUMENT&& (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {continue;}String tagName = parser.getName();if (tagName.equals("activity")) {// 1Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,owner.baseHardwareAccelerated);if (a == null) {mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;return false;}owner.activities.add(a);} else if (tagName.equals("receiver")) {// 2Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false);if (a == null) {mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;return false;}owner.receivers.add(a);} else if (tagName.equals("service")) {Service s = parseService(owner, res, parser, attrs, flags, outError);if (s == null) {mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;return false;}owner.services.add(s);} else if (tagName.equals("provider")) {Provider p = parseProvider(owner, res, parser, attrs, flags, outError);if (p == null) {mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;return false;}owner.providers.add(p);} else if (tagName.equals("activity-alias")) {Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError);if (a == null) {mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;return false;}owner.activities.add(a);} else if (parser.getName().equals("meta-data")) {// note: application meta-data is stored off to the side, so it can// remain null in the primary copy (we like to avoid extra copies because// it can be large)if ((owner.mAppMetaData = parseMetaData(res, parser, attrs, owner.mAppMetaData,outError)) == null) {mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;return false;}} else if (tagName.equals("library")) {sa = res.obtainAttributes(attrs,com.android.internal.R.styleable.AndroidManifestLibrary);// Note: don't allow this value to be a reference to a resource// that may change.String lname = sa.getNonResourceString(com.android.internal.R.styleable.AndroidManifestLibrary_name);sa.recycle();if (lname != null) {lname = lname.intern();if (!ArrayUtils.contains(owner.libraryNames, lname)) {owner.libraryNames = ArrayUtils.add(owner.libraryNames, lname);}}XmlUtils.skipCurrentTag(parser);} else if (tagName.equals("uses-library")) {sa = res.obtainAttributes(attrs,com.android.internal.R.styleable.AndroidManifestUsesLibrary);// Note: don't allow this value to be a reference to a resource// that may change.String lname = sa.getNonResourceString(com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);boolean req = sa.getBoolean(com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,true);sa.recycle();if (lname != null) {lname = lname.intern();if (req) {owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);} else {owner.usesOptionalLibraries = ArrayUtils.add(owner.usesOptionalLibraries, lname);}}XmlUtils.skipCurrentTag(parser);} else if (tagName.equals("uses-package")) {// Dependencies for app installers; we don't currently try to// enforce this.XmlUtils.skipCurrentTag(parser);} else {if (!RIGID_PARSER) {Slog.w(TAG, "Unknown element under <application>: " + tagName+ " at " + mArchiveSourcePath + " "+ parser.getPositionDescription());XmlUtils.skipCurrentTag(parser);continue;} else {outError[0] = "Bad element under <application>: " + tagName;mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;return false;}}} }

可以看到上面就是我們最為熟悉的配置文件中的各種節點配置,包括四大組件,meta-data

等。

其中有一點可以注意下:activity節點和receiver節點處理類型都為Activity對象,這是因為activity和receiver節點結構一樣,類似于JavaBean結構。

activity和receiver節點結構:

<activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><receiver android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /></intent-filter></receiver>

節點中都有intent-filter,action節點。那么在上面parseBaseApplication()函數代碼塊中位置1和位置2的函數parseActivity()如下:

private Activity parseActivity(Package owner, Resources res,XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,boolean receiver, boolean hardwareAccelerated)throws XmlPullParserException, IOException {......// 1Activity a = new Activity(mParseActivityArgs, new ActivityInfo());......while ((type=parser.next()) != XmlPullParser.END_DOCUMENT&& (type != XmlPullParser.END_TAG|| parser.getDepth() > outerDepth)) {if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {continue;}if (parser.getName().equals("intent-filter")) {//2ActivityIntentInfo intent = new ActivityIntentInfo(a);if (!parseIntent(res, parser, attrs, true, intent, outError)) {return null;}if (intent.countActions() == 0) {Slog.w(TAG, "No actions in intent filter at "+ mArchiveSourcePath + " "+ parser.getPositionDescription());} else {a.intents.add(intent);}} else if (parser.getName().equals("meta-data")) {if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,outError)) == null) {return null;}}}...... }

13行直接匹配解析intent-filter節點,同時將parseIntent()函數返回的intent-filter放入activity對象中的intents集合中。

在第8行中,這個activity對象中會將信息轉為ActivityInfo,其中包括各種信息:name,

packageName等等

到這里基本一次解析就結束了,會將得到的信息存儲到對應的PackageParser中的對應的集合中,并將這部分信息傳遞到PMS中

那么一樣的道理,在其他文件路徑下的處理也類似,比如/data/app-private目錄

以上,為PMS原理簡單流程,后續可補充。

總結

以上是生活随笔為你收集整理的Android PMS原理总结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。