Android 應用程序管理機制

fmms 13年前發布 | 58K 次閱讀 Android Android開發 移動開發

         android應用程序管理主要由PackageManager這個類來管理,實現PackageManager這個抽象類的是ContextImpl.java。在ContextImpl.java中,有一個內部靜態類叫ApplicationPackageManager,實現了所有PackageManager的接口。

 static final class ApplicationPackageManager extends PackageManager {

..........

}

ApplicationPackageManager又是通過對IPackageManager封裝調用,來實現的。

 public PackageInfo getPackageInfo(String packageName, int flags)
                throws NameNotFoundException {
            try {
                PackageInfo pi = mPM.getPackageInfo(packageName, flags);
                if (pi != null) {
                    return pi;
                }
            } catch (RemoteException e) {
                throw new RuntimeException("Package manager has died", e);
            }

            throw new NameNotFoundException(packageName);
        }

這里的mPM就是IPackageManager,PackageManagerService就是對IPackageManager的實現。所以我們平時對PackageManager的調用,最終是的在PackageManagerService.java中實現的。在PackageManagerService.java每個方法的實現。

PackageManagerService啟動流程:

PackageManagerService(context, factoryTest)是包管理服務的主進程。它完成了對/system/app,/data/app,/system/framework,/data/app-private下的apk文件的解析。詳細流程如下:

1.建立java層的installerc層的installdsocket聯接,使得在上層的install,remove,dexopt等功能最終由installd在底層實現

2.建立PackageHandler消息循環,用于處理外部的apk安裝請求消息,如adb install,packageinstaller安裝apk時會發送消息

3.解析/system/etc/permissionxml文件(framework/base/data/etc/),包括platform.xml和系統支持的各種硬件模塊的feature.主要工作:

(1)建立底層user idsgroup ids 同上層permissions之間的映射;可以指定一個權限與幾個組ID對應。當一個APK被授予這個權限時,它也同時屬于這幾個組。

(2)給一些底層用戶分配權限,如給shell授予各種permission權限;把一個權限賦予一個UID,當進程使用這個UID運行時,就具備了這個權限。

(3) library,系統增加的一些應用需要link的擴展jar庫;

(4) feature,系統每增加一個硬件,都要添加相應的feature.將解析結果放入mSystemPermissions,mSharedLibraries,mSettings.mPermissions,mAvailableFeatures等幾個集合中供系統查詢和權限配置使用。

4.檢查/data/system/packages.xml是否存在,這個文件是在解析apk時由

writeLP()創建的,里面記錄了系統的permissions,以及每個apkname,codePath,flags,version,uesrid等信息,這些信息主要通過apk

AndroidManifest.xml解析獲取,解析完apk后將更新信息寫入這個文件并保

存到flash,下次開機直接從里面讀取相關信息添加到內存相關列表中。當有apk

升級,安裝或刪除時會更新這個文件。

5.檢查BootClassPathmSharedLibraries/system/framework下的jar

是否需要dexopt,需要的則通過dexopt進行優化

6.啟動AppDirObserver線程監測/system/framework,/system/app,/data/app,/data/

app-private目錄的事件,主要監聽addremove事件。對于目錄監聽底層通過

inotify機制實現,inotify 是一種文件系統的變化通知機制,如文件增加、刪除

等事件可以立刻讓用戶態得知,它為用戶態監視文件系統的變化提供了強大的支持。

當有add event時調用scanPackageLI(File , int , int)處理;

當有remove event時調用removePackageLI()處理;

7.對于以上幾個目錄下的apk逐個解析,主要是解析每個apkAndroidMa-

nifest.xml文件,處理asset/res等資源文件,建立起每個apk的配置結構信息,

并將每個apk的配置信息添加到全局列表進行管理。f

8.將解析的每個apk的信息保存到packages.xmlpackages.list文件里,

packages.list記錄了如下數據:pkgNameuserIddebugFlagdataPath(包的數據路徑)

dexopt:

      如果我們想要求運行時的性能有進一步提高,就仍然需要對DEX文件進行進一步優化。優化DEX會產生一個可以快速載入執行的classes.dex文件,會進行包括byte-swapping,structure realigning與basic structure checks,更新ODEX header ,為了確保產生ODEX流程的正確性,Android提供了一個dexopt工具,用來做為虛擬機的輔助工具,可以在系統啟動時,透過Dalvik虛擬機對載入的DEX文件執行佳化操作。
 

優化發生的時機有兩個:

對于預置應用,可以在系統編譯后,生成優化文件,以ODEX 結尾。這樣在發布時除

APK 文件(不包含 DEX)以外,還有一個相應的 ODEX 文件;
  對于非預置應用,包含在 APK 文件里的 DEX 文件會在運行時通過dexopt進行優化,優化后的文件將被保存在緩存中(data/dalvik-cache)。   

android安全機制概述:

      Android是一個權限分離的系統 ,這是利用Linux已有的權限管理機制,通過為每一個Application分配不同的uid和gid, 從而使得不同的Application之間的私有數據和訪問(native以及java層通過這種sandbox機制)達到隔離的目的 。與此同時,Android還在此基礎上進行擴展,提供了permission機制,它主要是用來對Application可以執行的某些具體操作進行權限細分和訪問控制,同時提供了per-URI permission機制,用來提供對某些特定的數據塊進行訪問。
       Application 級別通過user ID和group Id實現安全控制;component級別通過permission來限制對于某一組件的訪問;在data級別通過基于permission的per URI進行安全控制。

 uid  gid  gids:

       Android 的權限分離的基礎是建立在 Linux 已有的 uid 、 gid 、 gids 基礎上的 。
UID :Android 在 安裝一個應用程序,就會為 它 分配一個 uid 。其中普通 Android 應用程序的 uid 是從 10000 開始分配 (Process.FIRST_APPLICATION_UID ), 10000 以下是系統進程的 uid 。
GID :對 于普通應用程序來說, gid 等于 uid 。由于每個應用程序的 uid 和 gid 都不相同, 因此不管是 native 層還是 java 層都能夠達到保護私有數據的作用 。
GIDS : gids 是由框架在 Application 安裝過程中生成,與 Application 申請的具體權限相關。 如果 Application 申請的相應的 permission 被 granted ,而且中有對應的 gids , 那么這個Application 的 gids 中將包含這個gids 。

installer類:

構造方法中,首先會進行一些成員變量的初始化,比如mContext, mFactoryTest, mMetrics, mSettings等。
最重要的是初始化mInstaller這個變量:

  Installer installer = new Installer();
        if (installer.ping() && Process.supportsProcesses()) {
            mInstaller = installer;
        } else {
            mInstaller = null;
        }

Installer這個是PackageManager與底層C模塊進行通信的工具類,同socket進行通信,PackageManager所有對apk的安裝,卸載等操作都是通過Installer進行的。對Installer的調用首先會調用ping()來判斷socket是否已經連接。

連接方法:connect:

 private boolean connect() {
        if (mSocket != null) {
            return true;
        }
        Slog.i(TAG, "connecting...");
        try {
            mSocket = new LocalSocket();

            LocalSocketAddress address = new LocalSocketAddress(
                "installd", LocalSocketAddress.Namespace.RESERVED);

            mSocket.connect(address);

            mIn = mSocket.getInputStream();
            mOut = mSocket.getOutputStream();
        } catch (IOException ex) {
            disconnect();
            return false;
        }
        return true;
    }
transaction首先會判斷連接,如果socket連接正常,就將cmd命令寫入socket文件,并且接收返回信息,并且返回給execute:
private synchronized String transaction(String cmd) {
        if (!connect()) {
            Slog.e(TAG, "connection failed");
            return "-1";
        }

        if (!writeCommand(cmd)) {
                /* If installd died and restarted in the background
                 * (unlikely but possible) we'll fail on the next
                 * write (this one).  Try to reconnect and write
                 * the command one more time before giving up.
                 */
            Slog.e(TAG, "write command failed? reconnect!");
            if (!connect() || !writeCommand(cmd)) {
                return "-1";
            }
        }
//        Slog.i(TAG,"send: '"+cmd+"'");
        if (readReply()) {
            String s = new String(buf, 0, buflen);
//            Slog.i(TAG,"recv: '"+s+"'");
            return s;
        } else {
//            Slog.i(TAG,"fail");
            return "-1";
        }

    }

 

執行命令的方法:execute(String cmd):

 
  private int execute(String cmd) {
        String res = transaction(cmd);
        try {
            return Integer.parseInt(res);
        } catch (NumberFormatException ex) {
            return -1;
        }
    }
install()方法:
    public int install(String name, int uid, int gid) {
        StringBuilder builder = new StringBuilder("install");
        builder.append(' ');
        builder.append(name);
        builder.append(' ');
        builder.append(uid);
        builder.append(' ');
        builder.append(gid);
        return execute(builder.toString());
    }

其他方法:

(1)  dexopt(String apkPath, int uid, boolean isPublic);優化dex文件
(2)movedex(String srcPath, String dstPath); 移動dex文件
(3)rmdex(String codePath);刪除dex文件
(4)remove(String name);移動apk
(5)rename(String oldname, String newname);重命名
(6)deleteCacheFiles(String name);刪除cache文件
(7)clearUserData(String name);刪除user data
(8)freeCache(long freeStorageSize);釋放cache空間
(9)setForwardLockPerm(String packagePathSuffix, int gid) 為apk文件增加前綴
(10)getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath, PackageStats pStats)  獲取apk信息
(11) moveFiles();移動文件。

 本文由用戶 fmms 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!