<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                下面開始分析構造函數第一階段的工作,先看如下所示的代碼。 **PackageManagerService.java::構造函數** ~~~ public PackageManagerService(Context context,boolean factoryTest, booleanonlyCore) { ...... if(mSdkVersion <= 0) { /* mSdkVersion是PKMS的成員變量,定義的時候進行賦值,其值取自系統屬性 “ro.build.version.sdk”,即編譯的SDK版本。如果沒有定義,則APK 就無法知道自己運行在Android哪個版本上 */ Slog.w(TAG, "**** ro.build.version.sdk not set!");//打印一句警告 } mContext = context; mFactoryTest= factoryTest;//假定為false,即運行在非工廠模式下 mOnlyCore = onlyCore;//假定為false,即運行在普通模式下 //如果此系統是eng版,則掃描Package后,不對package做dex優化 mNoDexOpt ="eng".equals(SystemProperties.get("ro.build.type")); //mMetrics用于存儲與顯示屏相關的一些屬性,例如屏幕的寬/高尺寸,分辨率等信息 mMetrics = new DisplayMetrics(); //Settings是一個非常重要的類,該類用于存儲系統運行過程中的一些設置, //下面進行詳細分析 mSettings = new Settings(); //①addSharedUserLPw是什么?馬上來分析 mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.phone", MULTIPLE_APPLICATION_UIDS //該變量的默認值是true ? RADIO_UID :FIRST_APPLICATION_UID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.log", MULTIPLE_APPLICATION_UIDS ? LOG_UID :FIRST_APPLICATION_UID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.nfc", MULTIPLE_APPLICATION_UIDS ? NFC_UID :FIRST_APPLICATION_UID, ApplicationInfo.FLAG_SYSTEM); ......//第一段結束 ~~~ 剛進入構造函數,就會遇到第一個較為復雜的數據結構Setting及它的addSharedUserLPw函數。Setting的作用是管理Android系統運行過程中的一些設置信息。到底是哪些信息呢?來看下面的分析。 1. 初識Settings 先分析addSharedUserLPw函數。此處截取該函數的調用代碼,如下所示: ~~~ mSettings.addSharedUserLPw("android.uid.system",//字符串 Process.SYSTEM_UID, //系統進程使用的用戶id,值為1000 ApplicationInfo.FLAG_SYSTEM//標志系統Package ); ~~~ 以此處的函數調用為例,我們為addSharedUserLPw傳遞了3個參數: 第一個是字符串“android.uid.system“;第二個是SYSTEM_UID,其值為1000;第三個是FLAG_SYSTEM標志,用于標識系統Package。 在進入對addSharedUserLPw函數的分析前,先介紹一下SYSTEM_UID 及相關知識。 (1) Android系統中UID/GID介紹 UID為用戶ID的縮寫,GID為用戶組ID的縮寫,這兩個概念均與Linux系統中進程的權限管理有關。一般說來,每一個進程都會有一個對應的UID(即表示該進程屬于哪個user,不同user有不同權限)。一個進程也可分屬不同的用戶組(每個用戶組都有對應的權限)。 >[info] **提示**:Linux的UID/GID還可細分為幾種類型,此處我們僅考慮普適意義的UID/GID。 如上所述,UID/GID和進程的權限有關。在Android平臺中,系統定義的UID/GID在Process.java文件中,如下所示: **Process.java** ~~~ //系統進程使用的UID/GID,值為1000 publicstatic final int SYSTEM_UID = 1000; //Phone進程使用的UID/GID,值為1001 publicstatic final int PHONE_UID = 1001; //shell進程使用的UID/GID,值為2000 publicstatic final int SHELL_UID = 2000; //使用LOG的進程所在的組的UID/GID為1007 publicstatic final int LOG_UID = 1007; //供WIF相關進程使用的UID/GID為1010 publicstatic final int WIFI_UID = 1010; //mediaserver進程使用的UID/GID為1013 publicstatic final int MEDIA_UID = 1013; //設置能讀寫SD卡的進程的GID為1015 publicstatic final int SDCARD_RW_GID = 1015; //NFC相關的進程的UID/GID為1025 publicstatic final int NFC_UID = 1025; //有權限讀寫內部存儲的進程的GID為1023 publicstatic final int MEDIA_RW_GID = 1023; //第一個應用Package的起始UID為10000 publicstatic final int FIRST_APPLICATION_UID = 10000; //系統所支持的最大的應用Package的UID為99999 publicstatic final int LAST_APPLICATION_UID = 99999; //和藍牙相關的進程的GID為2000 publicstatic final int BLUETOOTH_GID = 2000; ~~~ 對不同的UID/GID授予不同的權限,接下來就介紹和權限設置相關的代碼。 >[info] **提示**:讀者可用adb shell(將什么?)登錄到自己的手機,然后用busybox提供的ps命令查看進程的UID。 下面分析addSharedUserLPw函數,代碼如下: **Settings.java** ~~~ SharedUserSetting addSharedUserLPw(String name,int uid, int pkgFlags) { /* 注意這里的參數:name為字符串”android.uid.system”,uid為1000,pkgFlags為 ApplicationInfo.FLAG_SYSETM(以后簡寫為FLAG_SYSTEM) */ //mSharedUsers是一個HashMap,key為字符串,值為SharedUserSetting對象 SharedUserSetting s = mSharedUsers.get(name); if(s != null) { if (s.userId == uid) { return s; }...... return null; } //創建一個新的SharedUserSettings對象,并設置的userId為uid, //SharedUserSettings是什么?有什么作用? s =new SharedUserSetting(name, pkgFlags); s.userId = uid; if(addUserIdLPw(uid, s, name)) { mSharedUsers.put(name, s);//將name與s鍵值對添加到mSharedUsers中保存 return s; } return null; } ~~~ 從以上代碼可知,Settings中有一個mSharedUsers成員,該成員存儲的是字符串與SharedUserSetting鍵值對,也就是說以字符串為key得到對應的SharedUserSetting對象。 那么SharedUserSettings是什么?它的目的是什么?來看一個例子。 (2) SharedUserSetting分析 該例子來源于SystemUI的AndroidManifest.xml,如下所示: **SystemUI的AndroidManifest.xml** ~~~ <manifestxmlns:android="http://schemas.android.com/apk/res/android" package="com.android.systemui" coreApp="true" android:sharedUserId="android.uid.system" android:process="system"> ...... ~~~ 在xml中,聲明了一個名為android:sharedUserId的屬性,其值為“android.uid.system”。sharedUserId看起來和UID有關,確實如此,它有兩個作用: - 兩個或多個聲明了同一種sharedUserIds的APK可共享彼此的數據,并且可運行在同一進程中。 - 更重要的是,通過聲明特定的sharedUserId,該APK所在進程將被賦予指定的UID。例如,本例中的SystemUI聲明了system的uid,運行SystemUI的進程就可享有system用戶所對應的權限(實際上就是將該進程的uid設置為system的uid)了。 >[info] **提示**:除了在AndroidManifest.xml中聲明sharedUserId外,APK在編譯時還必須使用對應的證書進行簽名。例如本例的SystemUI,在其Android.mk中需要額外聲明LOCAL_CERTIFICATE := platform,如此,才可獲得指定的UID。 通過以上介紹,讀者能知道如何組織一種數據結構來包括上面的內容。此處有三個關鍵點需注意: - XML中sharedUserId屬性指定了一個字符串,它是UID的字符串描述,故對應數據結構中也應該有這樣一個字符串,這樣就把代碼和XML中的屬性聯系起來了。 - 在Linux系統中,真正的UID是一個整數,所以該數據結構中必然有一個整型變量。 - 多個Package可聲明同一個sharedUserId,因此該數據結構必然會保存那些聲明了相同sharedUserId的Package的某些信息。 了解了上面三個關鍵點,再來看Android是如何設計相應數據結構的,如圖4-2所示。 :-: ![](http://img.blog.csdn.net/20150803110344641?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖4-2 SharedUserSetting類的關系圖 由圖4-2可知: - Settings類定義了一個mSharedUsers成員,它是一個HashMap,以字符串(如“android.uid.system”)為Key,對應的Value是一個SharedUserSettings對象。 - SharedUserSetting派生自GrantedPermissions類,從GrantedPermissions類的命名可知,它和權限有關。SharedUserSetting定義了一個成員變量packages,類型為HashSet,用于保存聲明了相同sharedUserId的Package的權限設置信息。 - 每個Package有自己的權限設置。權限的概念由PackageSetting類表達。該類繼承自PackagesettingBase,而PackageSettingBase又繼承自GrantedPermissions。 - Settings中還有兩個成員,一個是mUserIds,另一個是mOtherUserIds,這兩位成員的類型分別是ArrayList和SparseArray。其目的是以UID為索引,得到對應的SharedUserSettings對象。在一般情況下,以索引獲取數組元素的速度,比以key獲取HashMap中元素的速度要快很多。 >[info] **提示 **:根據以上對mUserIds和mOtherUserIds的描述,可知這是典型的以空間換時間的做法。 下邊來分析addUserIdLPw函數,它的功能就是將SharedUserSettings對象保存到對應的數組中,代碼如下: **Settings.java** ~~~ private boolean addUserIdLPw(int uid, Object obj, Objectname) { //uid不能超出限制。Android對UID進行了分類,應用APK所在進程的UID從10000開始, //而系統APK所在進程小于10000 if(uid >= PackageManagerService.FIRST_APPLICATION_UID + PackageManagerService.MAX_APPLICATION_UIDS){ return false; } if(uid >= PackageManagerService.FIRST_APPLICATION_UID) { int N = mUserIds.size(); //計算索引,其值是uid和FIRST_APPLICATION_UID的差 final int index = uid - PackageManagerService.FIRST_APPLICATION_UID; while (index >= N) { mUserIds.add(null); N++; } ......//判斷該索引位置的內容是否為空,為空才保存 mUserIds.set(index, obj);//mUserIds保存應用Package的UID }else { ...... mOtherUserIds.put(uid, obj);//系統Package的UID由mOtherUserIds保存 } return true; } ~~~ 至此,對Settings的分析就告一段落了。在這次“行程”中,我們重點分析了UID/GID以及SharedUserId方面的知識,并見識好幾個重要的數據結構。希望讀者通過SystemUI的實例能夠理解這些數據結構存在的目的。 2. XML文件掃描 下面繼續分析PKMS的構造函數,代碼如下: **PackageMangerService.java::構造函數** ~~~ ......//接前一段 String separateProcesses = //該值和調試有關。一般不設置該屬性 SystemProperties.get("debug.separate_processes"); if(separateProcesses != null && separateProcesses.length() > 0) { ...... }else { mDefParseFlags = 0; mSeparateProcesses = null; } //創建一個Installer對象,該對象和Native進程installd交互,以后分析installd //時再來討論它的作用 mInstaller = new Installer(); WindowManager wm = //得到一個WindowManager對象 (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); Display d = wm.getDefaultDisplay(); d.getMetrics(mMetrics); //獲取當前設備的顯示屏信息 synchronized (mInstallLock) { synchronized (mPackages) { //創建一個ThreadHandler對象,實際就是創建一個帶消息循環處理的線程,該線程 //的工作是:程序的和卸載等。以后分析程序安裝時會和它親密接觸 mHandlerThread.start(); //以ThreadHandler線程的消息循環(Looper對象)為參數創建一個PackageHandler, //可知該Handler的handleMessage函數將運行在此線程上 mHandler = new PackageHandler(mHandlerThread.getLooper()); File dataDir = Environment.getDataDirectory(); // mAppDataDir指向/data/data目錄 mAppDataDir = new File(dataDir, "data"); // mUserAppDataDir指向/data/user目錄 mUserAppDataDir = new File(dataDir, "user"); // mDrmAppPrivateInstallDir指向/data/app-private目錄 mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); /* 創建一個UserManager對象,目前沒有什么作用,但其前途將不可限量。 根據Google的設想,未來手機將支持多個User,每個User將安裝自己的應用, 該功能為Andorid智能手機推向企業用戶打下堅實基礎 */ mUserManager = new UserManager(mInstaller, mUserAppDataDir); //①從文件中讀權限 readPermissions(); //②readLPw分析 mRestoredSettings = mSettings.readLPw(); long startTime = SystemClock.uptimeMillis(); ~~~ 以上代碼中創建了幾個對象,此處暫可不去理會它們。另外,以上代碼中還調用了兩個函數,分別是readPermission和Setttings的readLPw,它們有什么作用呢?下面就展開分析。 (1) readPermissions函數分析 先來分析readPermissions函數,從其函數名可猜測到它和權限有關,代碼如下: **PackageManagerService.java** ~~~ void readPermissions() { // 指向/system/etc/permission目錄,該目錄中存儲了和設備相關的一些權限信息 FilelibraryDir = new File(Environment.getRootDirectory(), "etc/permissions"); ...... for(File f : libraryDir.listFiles()) { //先處理該目錄下的非platform.xml文件 if (f.getPath().endsWith("etc/permissions/platform.xml")) { continue; } ......//調用readPermissionFromXml解析此XML文件 readPermissionsFromXml(f); } finalFile permFile = new File(Environment.getRootDirectory(), "etc/permissions/platform.xml"); //解析platform.xml文件,看來該文件優先級最高 readPermissionsFromXml(permFile); } ~~~ 懸著的心終于放了下來!readPermissions函數不就是調用readPermissionFromXml函數解析/system/etc/permissions目錄下的文件嗎?這些文件似乎都是XML文件。該目錄下都有哪些XML文件呢?這些XML文件中有些什么內容呢?來看一個實際的例子,如圖4-3所示。 :-: ![](http://img.blog.csdn.net/20150803110405552?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖4-3 /system/etc/permissions目錄下的內容 圖4-3中列出的是本人G7手機上/system/etc/permissions目錄下的內容。在上面的代碼中,雖然最后才解析platform.xml文件, 不過此處先分析此文件其內容如下所示: **platform.xml** ~~~ <permissions> <!--建立權限名與gid的映射關系。如下面聲明的BLUTOOTH_ADMIN權限,它對應的用戶組是 net_bt_admin。注意,該文件中的permission標簽只對那些需要通過讀寫設備(藍牙/camera) /創建socket等進程劃分了gid。因為這些權限涉及和Linux內核交互,所以需要在底層 權限(由不同的用戶組界定)和Android層權限(由不同的字符串界定)之間建立映射關系 --> <permission name="android.permission.BLUETOOTH_ADMIN" > <group gid="net_bt_admin" /> </permission> <permission name="android.permission.BLUETOOTH" > <group gid="net_bt" /> </permission> ...... <!-- 賦予對應uid相應的權限。如果下面一行表示uid為shell,那么就賦予 它SEND_SMS的權限,其實就是把它加到對應的用戶組中--> <assign-permission name="android.permission.SEND_SMS"uid="shell" /> <assign-permission name="android.permission.CALL_PHONE"uid="shell" /> <assign-permission name="android.permission.READ_CONTACTS"uid="shell" /> <assign-permission name="android.permission.WRITE_CONTACTS"uid="shell" /> <assign-permissionname="android.permission.READ_CALENDAR" uid="shell" /> ...... <!-- 系統提供的Java庫,應用程序運行時候必須要鏈接這些庫,該工作由系統自動完成 --> <libraryname="android.test.runner" file="/system/frameworks/android.test.runner.jar" /> <library name="javax.obex" file="/system/frameworks/javax.obex.jar"/> </permissions> ~~~ platform.xml文件中主要使用了如下4個標簽: - permission和group用于建立Linux層gid和Android層pemission之間的映射關系。 - assign-permission用于向指定的uid賦予相應的權限。這個權限由Android定義,用字符串表示。 - library用于指定系統庫。當應用程序運行時,系統會自動為這些進程加載這些庫。 了解了platform.xml后,再看其他的XML文件,這里以handheld-core-hardware.xml為例進行介紹,其內容如下: **handheld-core-hardware.xml** ~~~ <permissions> <feature name="android.hardware.camera" /> <feature name="android.hardware.location" /> <feature name="android.hardware.location.network" /> <feature name="android.hardware.sensor.compass" /> <feature name="android.hardware.sensor.accelerometer" /> <feature name="android.hardware.bluetooth" /> <feature name="android.hardware.touchscreen" /> <feature name="android.hardware.microphone" /> <feature name="android.hardware.screen.portrait" /> <feature name="android.hardware.screen.landscape" /> </permissions> ~~~ 這個XML文件包含了許多feature標簽。根據該文件中的注釋,這些feature用來描述一個手持終端(包括手機、平板電腦等)應該支持的硬件特性,例如支持camera、支持藍牙等。 * * * * * **注意**:對于不同的硬件特性,還需要包含其他的xml文件。例如,要支持前置攝像頭,還需要包含android.hardware.camera.front.xml文件。這些文件內容大體一樣,都通過feature標簽表明自己的硬件特性。相關說明可參考handheld-core-hardware.xml中的注釋。 * * * * * 有讀者可能會好奇,真實設備上/system/etc/permission目錄中的文件是從哪里的呢? 答案是,在編譯階段由不同硬件平臺根據自己的配置信息復制相關文件到目標目錄中得來的。 這里給出一個例子,如圖4-4所示。 :-: ![](http://img.blog.csdn.net/20150803110433019?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖4-4 /system/etc/permission目錄中文件的來源 由圖4-4可知,當編譯的設備目標為htc-passion時,就會將Android源碼目錄/frameworks/base/data/etc/下某些和該目標設備硬件特性匹配的XML文件復制到最終輸出目錄/system/etc/permissions下。編譯完成后,將生成system鏡像。把該鏡像文件燒到手機中,就成了目標設備使用的情況了。 * * * * * **注意**:4.0源碼中并沒有htc相關的文件,這是筆者從2.3源碼中移植過去的。讀者可參考筆者一篇關于如何移植4.0到G7的博文,地址為[http://blog.csdn.net/innost/article/details/6977167](http://blog.csdn.net/innost/article/details/6977167) * * * * * 了解了與XML相關的知識后,再來分析readPermissionFromXml函數。相信聰明的讀者已經知道它的作用了,就是將XML文件中的標簽以及它們之間的關系轉換成代碼中的相應數據結構,代碼如下: **PackageManagerService.java** ~~~ private void readPermissionsFromXml(File permFile){ FileReader permReader = null; try{ permReader = new FileReader(permFile); } ...... try{ XmlPullParser parser = Xml.newPullParser(); parser.setInput(permReader); XmlUtils.beginDocument(parser, "permissions"); while (true) { ...... String name = parser.getName(); //解析group標簽,前面介紹的XML文件中沒有單獨使用該標簽的地方 if ("group".equals(name)) { String gidStr = parser.getAttributeValue(null, "gid"); if (gidStr != null) { int gid =Integer.parseInt(gidStr); //轉換XML中的gid字符串為整型,并保存到mGlobalGids中 mGlobalGids =appendInt(mGlobalGids, gid); } ...... } else if ("permission".equals(name)) {//解析permission標簽 String perm = parser.getAttributeValue(null, "name"); ...... perm = perm.intern(); //調用readPermission處理 readPermission(parser, perm); //下面解析的是assign-permission標簽 } else if("assign-permission".equals(name)) { String perm = parser.getAttributeValue(null, "name"); ...... String uidStr = parser.getAttributeValue(null, "uid"); ...... //如果是assign-permission,則取出uid字符串,然后獲得Linux平臺上 //的整型uid值 int uid = Process.getUidForName(uidStr); ...... perm = perm.intern(); //和assign相關的信息保存在mSystemPermissions中 HashSet<String> perms = mSystemPermissions.get(uid); if (perms == null) { perms = newHashSet<String>(); mSystemPermissions.put(uid, perms); } perms.add(perm);...... } else if ("library".equals(name)) {//解析library標簽 String lname = parser.getAttributeValue(null, "name"); String lfile = parser.getAttributeValue(null, "file"); if (lname == null) { ...... } else if (lfile == null) { ...... } else { //將XML中的name和library屬性值存儲到mSharedLibraries中 mSharedLibraries.put(lname,lfile); } ...... } else if ("feature".equals(name)) {//解析feature標簽 String fname = parser.getAttributeValue(null, "name"); ......{ //在XML中定義的feature由FeatureInfo表達 FeatureInfo fi = newFeatureInfo(); fi.name = fname; //存儲feature名和對應的FeatureInfo到mAvailableFeatures中 mAvailableFeatures.put(fname, fi); }...... } ...... } ...... } ~~~ readPermissions函數果然將XML中的標簽轉換成對應的數據結構。總結相關的數據結構,如圖4-4所示,此處借用了UML類圖。在每個類圖中,首行是數據結構名,第二行是數據結構的類型,第三行是注釋。 :-: ![](http://img.blog.csdn.net/20150803110509033?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖4-4 通過readPermissions函數建立的數據結構及其關系 這里必須再次強調:圖4-4中各種數據結構的目的是為了保存XML中各種標簽及它們之間的關系。在分析過程中,最重要的是理解各種標簽的作用,而不是它們所使用的數據結構。 (2) readLPw的“佐料” readLPw函數的功能也是解析文件,不過這些文件的內容卻是在PKMS正常啟動后生成的。這里僅介紹作為readLPw“佐料”的文件的信息。文件的具體位置在Settings構造函數中指明,其代碼如下: **Settings.java** ~~~ Settings() { FiledataDir = Environment.getDataDirectory(); FilesystemDir = new File(dataDir, "system");//指向/data/system目錄 systemDir.mkdirs();//創建該目錄 ...... /* 一共有5個文件,packages.xml和packages-backup.xml為一組,用于描述系統中 所安裝的Package的信息,其中backup是臨時文件。PKMS先把數據寫到backup中, 信息都寫成功后再改名成非backup的文件。其目的是防止在寫文件過程中出錯,導致信息丟失。 packages-stopped.xml和packages-stopped-backup.xml為一組,用于描述系統中 強制停止運行的pakcage的信息,backup也是臨時文件。如果此處存在該臨時文件,表明 此前系統因為某種原因中斷了正常流程 packages.list列出當前系統中應用級(即UID大于10000)Package的信息 */ mSettingsFilename = new File(systemDir, "packages.xml"); mBackupSettingsFilename = new File(systemDir,"packages-backup.xml"); mPackageListFilename = new File(systemDir, "packages.list"); mStoppedPackagesFilename = new File(systemDir,"packages-stopped.xml"); mBackupStoppedPackagesFilename = new File(systemDir, "packages-stopped-backup.xml"); } ~~~ 上面5個文件共分為三組,這里簡單介紹一下這些文件的來歷(不考慮臨時的backup文件)。 - packages.xml: PKMS掃描完目標文件夾后會創建該文件。當系統進行程序安裝、卸載和更新等操作時,均會更新該文件。該文件保存了系統中與package相關的一些信息。 - packages.list:描述系統中存在的所有非系統自帶的APK的信息。當這些程序有變動時,PKMS就會更新該文件。 - packages-stopped.xml:從系統自帶的設置程序中進入應用程序頁面,然后在選擇強制停止(ForceStop)某個應用時,系統會將該應用的相關信息記錄到此文件中。也就是該文件保存系統中被用戶強制停止的Package的信息。 readLPw的函數功能就是解析其中的XML文件的內容,然后建立并更新對應的數據結構,例如停止的package重啟之后依然是stopped狀態。 * * * * * **提示**:讀者看完本章后,可自行分析該函數。在此之前,建議讀者不必關注該函數。 * * * * * 3. 第一階段工作總結 在繼續征程前,先總結一下PKMS構造函數在第一階段的工作,千言萬語匯成一句話:掃描并解析XML文件,將其中的信息保存到特定的數據結構中。 第一階段掃描的XML文件與權限及上一次掃描得到的Package信息有關,它為PKMS下一階段的工作提供了重要的參考信息。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看