PackageManagerService 系列文章以下(基於 Android 9.0 源碼)
🍁 Framework 核心服務之 PackageManagerService 鑽研(1)- 啓動流程
🍁 Framework 核心服務之 PackageManagerService 鑽研(2)- 構造函數
🍁 Framework 核心服務之 PackageManagerService 鑽研(3)- PackageManager
🍁 Framework 核心服務之 PackageManagerService 鑽研(4)- PackageInstaller
🍁 Framework 核心服務之 PackageManagerService 鑽研(5)- APK 安裝流程(PackageInstaller)
🍁 Framework 核心服務之 PackageManagerService 鑽研(6)- APK 安裝流程(PMS)
🍁 Framework 核心服務之 PackageManagerService 鑽研(7)- PackageParserjava
關鍵類 | 路徑 |
---|---|
Context.java | frameworks/base/core/java/android/content/Context.java |
ContextImpl.java | frameworks/base/core/java/android/app/ContextImpl.java |
PackageManager.java | frameworks/base/core/java/android/content/pm/PackageManager.java |
ApplicationPackageManager.java | frameworks/base/core/java/android/app/ApplicationPackageManager.java |
ActivityThread.java | frameworks/base/core/java/android/app/ActivityThread.java |
PackageManager 是一個抽象類:android
/** * Class for retrieving various kinds of information related to the application * packages that are currently installed on the device. * * You can find this class through {@link Context#getPackageManager}. */ public abstract class PackageManager {
註釋能夠看出:PackageManager 這個類是檢測當前已經安裝在當前設備上的應用程序包的信息。你能夠調用 Context 類的 getPackageManager() 方法來獲取 PackageManager。segmentfault
PackageManager 是一個實際上管理應用程序安裝、卸載和升級的 API。當咱們安裝 APK 文件時,PackageManager 會解析 APK 包文件和顯示確認信息。當咱們點擊 OK 按鈕後,PackageManager 會調用一個叫 "InstallPackage" 的方法,這個方法有 4 個參數,也就是 uri、installFlags、observer、installPackagename。PackageManager 會啓動一個叫 "package" 的 servcie 服務,如今全部模糊的東西會發生在這個 service 中。緩存
✨ 一、安裝、卸載應用
✨ 二、查詢 permission 相關信息
✨ 三、查詢 Application 相關信息(application、activity、receiver、service、provider 及相應屬性等)
✨ 四、查詢已安裝應用
✨ 五、增長、刪除 permission
✨ 六、清除用戶數據、緩存、代碼等安全
/** * Retrieve overall information about an application package that is * installed on the system. * * @param packageName The full name (i.e. com.google.apps.contacts) of the * desired package. * @param flags Additional option flags to modify the data returned. * @return A PackageInfo object containing information about the package. If * flag {@code MATCH_UNINSTALLED_PACKAGES} is set and if the package * is not found in the list of installed applications, the package * information is retrieved from the list of uninstalled * applications (which includes installed applications as well as * applications with data directory i.e. applications which had been * deleted with {@code DONT_DELETE_DATA} flag set). * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 經過包名獲取該包名對應的應用程序的 PackageInfo 對象, * PackageInfo 類包含了從 AndroidManifest.xml 文件中收集的全部信息。 */ public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) throws NameNotFoundException;
/** * Retrieve all of the information we know about a particular * package/application. * * @param packageName The full name (i.e. com.google.apps.contacts) of an * application. * @param flags Additional option flags to modify the data returned. * @return An {@link ApplicationInfo} containing information about the * package. If flag {@code MATCH_UNINSTALLED_PACKAGES} is set and if * the package is not found in the list of installed applications, * the application information is retrieved from the list of * uninstalled applications (which includes installed applications * as well as applications with data directory i.e. applications * which had been deleted with {@code DONT_DELETE_DATA} flag set). * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 根據包名返回其對應的 ApplicationInfo 信息。 */ public abstract ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags) throws NameNotFoundException;
/** * Retrieve all of the information we know about a particular activity * class. * * @param component The full component name (i.e. * com.google.apps.contacts/com.google.apps.contacts. * ContactsList) of an Activity class. * @param flags Additional option flags to modify the data returned. * @return An {@link ActivityInfo} containing information about the * activity. * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 檢索出一個特定的 Activity 類的全部信息。 */ public abstract ActivityInfo getActivityInfo(ComponentName component, @ComponentInfoFlags int flags) throws NameNotFoundException;
/** * Retrieve all of the information we know about a particular receiver * class. * * @param component The full component name (i.e. * com.google.apps.calendar/com.google.apps.calendar. * CalendarAlarm) of a Receiver class. * @param flags Additional option flags to modify the data returned. * @return An {@link ActivityInfo} containing information about the * receiver. * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 檢索出一個特定的 Receiver 類的全部信息(這裏主要指 ActivityInfo)。 */ public abstract ActivityInfo getReceiverInfo(ComponentName component, @ComponentInfoFlags int flags) throws NameNotFoundException;
/** * Retrieve all of the information we know about a particular service class. * * @param component The full component name (i.e. * com.google.apps.media/com.google.apps.media. * BackgroundPlayback) of a Service class. * @param flags Additional option flags to modify the data returned. * @return A {@link ServiceInfo} object containing information about the * service. * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 檢索出一個特定的 Service 類的全部信息(這裏主要指 ServiceInfo)。 */ public abstract ServiceInfo getServiceInfo(ComponentName component, @ComponentInfoFlags int flags) throws NameNotFoundException;
/** * Retrieve all of the information we know about a particular content * provider class. * * @param component The full component name (i.e. * com.google.providers.media/com.google.providers.media. * MediaProvider) of a ContentProvider class. * @param flags Additional option flags to modify the data returned. * @return A {@link ProviderInfo} object containing information about the * provider. * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 檢索出一個特定的 content provider 類的全部信息(這裏主要指 ProviderInfo)。 */ public abstract ProviderInfo getProviderInfo(ComponentName component, @ComponentInfoFlags int flags) throws NameNotFoundException;
/** * Return a List of all packages that are installed for the current user. * * @param flags Additional option flags to modify the data returned. * @return A List of PackageInfo objects, one for each installed package, * containing information about the package. In the unlikely case * there are no installed packages, an empty list is returned. If * flag {@code MATCH_UNINSTALLED_PACKAGES} is set, the package * information is retrieved from the list of uninstalled * applications (which includes installed applications as well as * applications with data directory i.e. applications which had been * deleted with {@code DONT_DELETE_DATA} flag set). * * 獲取設備上安裝的全部軟件包。 */ public abstract List<PackageInfo> getInstalledPackages(@PackageInfoFlags int flags);
/** * Map from the current package names in use on the device to whatever * the current canonical name of that package is. * @param names Array of current names to be mapped. * @return Returns an array of the same size as the original, containing * the canonical name for each package. * * 從設備上使用當前包名映射到該軟件包名的當前規範名稱, * 若是修改包名會用到,沒有修改過包名通常不會用到。 */ public abstract String[] currentToCanonicalPackageNames(String[] names);
/** * Map from a packages canonical name to the current name in use on the device. * @param names Array of new names to be mapped. * @return Returns an array of the same size as the original, containing * the current name for each package. * * 將軟件包規範名稱映射到設備上正在使用的當前名稱, * 咱們發現:canonicalToCurrentPackageNames() 和 currentToCanonicalPackageNames() 方法是相反的兩個方法 */ public abstract String[] canonicalToCurrentPackageNames(String[] names);
/** * Retrieve all of the information we know about a particular permission. * * @param name The fully qualified name (i.e. com.google.permission.LOGIN) * of the permission you are interested in. * @param flags Additional option flags to modify the data returned. * @return Returns a {@link PermissionInfo} containing information about the * permission. * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 檢測出咱們想要知道的全部關於權限的信息。 */ public abstract PermissionInfo getPermissionInfo(String name, @PermissionInfoFlags int flags) throws NameNotFoundException;
/** * Query for all of the permissions associated with a particular group. * * @param group The fully qualified name (i.e. com.google.permission.LOGIN) * of the permission group you are interested in. Use null to * find all of the permissions not associated with a group. * @param flags Additional option flags to modify the data returned. * @return Returns a list of {@link PermissionInfo} containing information * about all of the permissions in the given group. * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 查詢與特定組相關的全部權限。 */ public abstract List<PermissionInfo> queryPermissionsByGroup(String group, @PermissionInfoFlags int flags) throws NameNotFoundException;
/** * Retrieve all of the known permission groups in the system. * * @param flags Additional option flags to modify the data returned. * @return Returns a list of {@link PermissionGroupInfo} containing * information about all of the known permission groups. * * 檢索出系統中全部已知的權限。 */ public abstract List<PermissionGroupInfo> getAllPermissionGroups( @PermissionGroupInfoFlags int flags);
固然除了上面列舉出來的方法之外,還有其餘不少方法,咱們再也不一一列出來,若是後面分析遇到會再單獨拿出來分析!app
接下來咱們來看看 PackageManager 中關於安裝的幾個方法!ide
/** * packageURI:表示安裝的路徑,能夠是 "file:" 或者 "content:" 的 URI * observer: 一個回調的觀察者,有了這個觀察者,就能夠在軟件包安裝完成後獲得安裝結果的通知。 * 若是安裝完成會調用這個觀察者 IPackageInstallObserver 的 packageInstalled(String,int)方法,observer這個入參不能爲空。 * flags: 標誌位參數 * nstallerPackageName:正在進行安裝的安裝包包名 */ /** * @deprecated replaced by {@link PackageInstaller} * @hide */ @Deprecated public abstract void installPackage( // 棄用 Uri packageURI, IPackageInstallObserver observer, @InstallFlags int flags, String installerPackageName); /** * @deprecated replaced by {@link PackageInstaller} * @hide */ @Deprecated public abstract void installPackage( // 棄用 Uri packageURI, PackageInstallObserver observer, @InstallFlags int flags, String installerPackageName);
從 8.1 開始,已經棄用了 installPackage 方法(9.0 的代碼中已經去除 installPackage 代碼了),而是使用 PackageInstaller 執行應用的安裝、升級和刪除操做。函數
/** * Return interface that offers the ability to install, upgrade, and remove * applications on the device. */ public abstract @NonNull PackageInstaller getPackageInstaller();
/** * If there is already an application with the given package name installed * on the system for other users, also install it for the calling user. * @hide */ @SystemApi // 系統 API public abstract int installExistingPackage(String packageName) throws NameNotFoundException;
經過註釋能夠看出這個方法的用途:若是系統上已經安裝相同包名的應用程序,則重複從新安裝。this
咱們知道 PackageManager 是一個抽象類,它裏面很重要的方法都是抽象的,因此在具體執行的時候,確定是它的實現子類,那麼咱們就來看下它的具體實現類。google
前面咱們講解 PackageManager 類的時候,官網推薦獲取 PackageManager 對象的方法是 Context 的 Context#getPackageManager() 方法,那咱們來看下:
// frameworks/base/core/java/android/content/Context.java /** Return PackageManager instance to find global package information. */ public abstract PackageManager getPackageManager();
咱們知道 Context 也是一個抽象類,而它的 getPackageManager() 也是抽象方法,但 Context 的具體實現類是 ContextImpl,那咱們就去 ContextImpl 裏面看下:
/** * Common implementation of Context API, which provides the base * context object for Activity and other application components. * @hide */ public class ContextImpl extends Context { private PackageManager mPackageManager; ... ... @Override public PackageManager getPackageManager() { // 判斷 mPackageManager 是否爲空,若是爲空,則說明是第一次調用 if (mPackageManager != null) { return mPackageManager; } // 調用 ActivityThread 的靜態方法 getPackageManager() 獲取一個 IPackageManager 對象 IPackageManager pm = ActivityThread.getPackageManager(); // 若是獲取的 IPackageManager 對象不爲空,則構造一個 ApplicationPackageManager 對象,ApplicationPackageManager 是 PackageManager 的子類 if (pm != null) { // Doesn't matter if we make more than one instance. return (mPackageManager = new ApplicationPackageManager(this, pm)); } return null; } ... ... }
因此,在咱們平時調用 Context 的 getPackageManager()方法後,其實返回的是 ApplicationPackageManager 這個類。
咱們先來看下 ApplicationPackageManager 類的源碼:
/** @hide */ public class ApplicationPackageManager extends PackageManager {
經過源碼咱們知道 ApplicationPackageManager 繼承自PackageManager,並且 ApplicationPackageManager 類不是抽象的,因此 ApplicationPackageManager 必然實現了 PackageManager 的全部抽象方法。
protected ApplicationPackageManager(ContextImpl context, IPackageManager pm) { mContext = context; mPM = pm; }
在講解 PackageManager 的時候,咱們提到過安裝 APK 會調用 InstallPackage 方法(Android 8.1,9.0 已棄用),咱們看下在 ApplicationPackageManager 中的具體實現:
@Override public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName) { installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags, installerPackageName, mContext.getUserId()); }
// 源碼來自:Android 8.1,9.0 已棄用 private void installCommon(Uri packageURI, PackageInstallObserver observer, int flags, String installerPackageName, int userId) { // scheme 判斷,若是非 "file" 則拋異常,由於只支持 file 格式的 URI if (!"file".equals(packageURI.getScheme())) { throw new UnsupportedOperationException("Only file:// URIs are supported"); } // 獲取相應的路徑 final String originPath = packageURI.getPath(); try { // 調用 installPackageAsUser 方法 mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName, userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
能夠發現,public abstract void installPackage() 方法其內部本質是調用的 IPackageManager 的 installPackageAsUser() 方法。
咱們先來看看以下代碼(上面沒有分析):
// 調用 ActivityThread 的靜態方法 getPackageManager() 獲取一個 IPackageManager 對象 IPackageManager pm = ActivityThread.getPackageManager();
跟蹤 getPackageManager():
static volatile IPackageManager sPackageManager; public static IPackageManager getPackageManager() { // 判斷 sPackageManager 是否爲空,若是爲空,則說明是的第一次調用,走第二步,若是不爲空,則直接返回 sPackageManager if (sPackageManager != null) { return sPackageManager; } // 能走到第二步,說明這是第一次調用,則調用 ServiceManager 的 getService(String) 方法獲取一個 IBinder 對象 IBinder b = ServiceManager.getService("package"); // 調用 IPackageManager.Stub.asInterface(IBinder) 獲取一個 sPackageManager 對象 sPackageManager = IPackageManager.Stub.asInterface(b); return sPackageManager; }
在上面分析 ContextImpl 的 getPackageManager() 方法裏面,咱們知道:
IPackageManager pm = ActivityThread.getPackageManager(); if (pm != null) { // Doesn't matter if we make more than one instance. return (mPackageManager = new ApplicationPackageManager(this, pm)); }
而在 ActivityThread 的靜態方法 getPackageManager() 裏面:
sPackageManager = IPackageManager.Stub.asInterface(b); return sPackageManager;
因此在 ApplicationPackageManager 裏面的 mPM 其實就是 IPackageManager.Stub 內部類 Proxy 對象。
那對應的 IPackageManager.Stub 是什麼?其實就是 PackageManagerService.java 。
public class PackageManagerService extends IPackageManager.Stub implements PackageSender {
以下圖所示:
結合上面的知識,再結合 PackageManager、ApplicationPackageManager 和 PackageManagerService 總結以下:
✨ IPackageManager 負責通訊:IPackageManager 接口類中定義了不少業務方法,可是因爲安全等方面的考慮,Android 對外(即SDK)提供的僅僅是一個子集,該子集被封裝在抽象類 PackageManager 中。客戶端通常經過 Context 的 getPackageManager 函數返回一個類型爲 PackageManager 的對象,該對象的實際類型是 PackageManager 的子類 ApplicationPackageManager 。ApplicationPackageManager 並無直接參與 Binder 通訊,而是經過 mPM 成員變量指向了一個 IPackageManager.Stub.Proxy 類型的對象。
✨ AIDL中 的 Binder 服務端是 PackageManagerService,由於 PackageManagerService 繼承自 IPackageManager.Stub 。因爲 IPackageManager.Stub 類從 Binder 派生,因此 PackageManagerService 將做爲服務端參與 Binder 通訊。
✨ AIDL中 的 Binder 客戶端是 ApplicationPackageManager 中成員變量 mPM,由於mPM內部指向的是 IPackageManager.Stub.Proxy。
總體流程的 Binder 結構大體以下:
01. https://www.jianshu.com/p/c56...
02. https://www.jianshu.com/p/a30...