天天看點

Android源碼之“應用程式界面“分析二(PackageManager和PackageManagerService)

Android源碼之“應用程式界面“分析二(PackageManager和PackageManagerService):

一。PackageManager:

上一篇中,我們用到了PackageManager的getPackageSizeInfo函數,來得到應用程式的詳細資訊,這一篇中,我們将深入PackageManager的内部,來一探究竟。

1. PackageManager類:

它是一個抽象類,我們僅僅列出幾個要讨論的函數:

定義: public abstract class PackageManager {

// @hide

public abstract void clearApplicationUserData(StringpackageName,

            IPackageDataObserver observer);

// @hide

public abstract void getPackageSizeInfo(String packageName,

            IPackageStatsObserver observer);

public void installPackage(Uri packageURI) {

        installPackage(packageURI,null, 0);

    }

說明:

1) Hide,意味着我們不能像上一篇文章中提到的settings中的實作方式來直接調用getPackageSizeInfo這樣的函數,也就是說,在我們的應用中,下面的做法是非法的:

PackageManager mPm = getPackageManager();

mSizeObserver = newPkgSizeObserver();

mPm.getPackageSizeInfo(packageName, mSizeObserver);

那麼,那麼,為了實作我們的功能,我們該如何做呢?

這就需要用到java反射機制,來調用android framework層的hide的函數。

在http://blog.csdn.net/liranke/article/details/13766349一篇文章中,較長的描述了這種實作方式。

2) 我們發現有installPackage這樣的函數,不難猜出,它是用來安裝應用程式的。

3) 再次提醒一下,這是一個定義為abstract的類,那麼,它的實作類在哪裡呢?

我們也沒有發現哪個類是繼承自它的啊。

事實上,實作它的類是在PackageManagerService中,而它的定義如下:

class PackageManagerService extends IPackageManager.Stub {

final Installer mInstaller;  // 非常重要

。。。

getPackageSizeInfo(。。。)

。。。},

這裡,我們僅僅以getPackageSizeInfo來做為例子進行分析。

2.    getPackageSizeInfo函數:

public void getPackageSizeInfo(final String packageName,

            final IPackageStatsObserverobserver) {

       mContext.enforceCallingOrSelfPermission(

                android.Manifest.permission.GET_PACKAGE_SIZE, null);

       // Queue up an async operation since the package deletion may take alittle while.

       mHandler.post(new Runnable() {

            public void run() {

                mHandler.removeCallbacks(this);

                PackageStats lStats = new PackageStats(packageName);

                final boolean succeded;

                synchronized (mInstallLock) {

                    succeded = getPackageSizeInfoLI(packageName,lStats);

                }

                if(observer != null) {

                    try {

                        observer.onGetStatsCompleted(lStats, succeded);

                    } catch (RemoteException e){

                        Log.i(TAG,"Observer no longer exists.");

                    }

                } //end if observer

            } //end run

       });

    }

   1)。需要注意,permission.GET_PACKAGE_SIZE權限。

  2)。PackageStats lStats将會存放着得到的資料,

 3)。getPackageSizeInfoLI是主要的函數。

4) 。onGetStatsCompleted, 我們需要實作的回調函數,這在上一篇文章中已經有展現。

那麼,在getPackageSizeInfoLI中,有:

int res = mInstaller.getSizeInfo(packageName,p.mPath,

                    publicSrcDir, pStats);

而mInstaller是Installer類型的一個執行個體,事實上,它是與android中的守護程序installd進行通信的,通過socket.

3.   Installer的定義如下:

class Installer {

    private static final String TAG ="Installer";

  InputStream mIn;

  OutputStream mOut;

  LocalSocket mSocket;

  byte buf[] = new byte[1024];

  int buflen = 0;

    private boolean connect() {

        if (mSocket != null) {

            return true;

        }

        Log.i(TAG, "connecting...");

        try {

            mSocket = new LocalSocket();

            LocalSocketAddress address = newLocalSocketAddress(

                "installd", LocalSocketAddress.Namespace.RESERVED);

            mSocket.connect(address);

            mIn = mSocket.getInputStream();

            mOut = mSocket.getOutputStream();

        } catch (IOException ex) {

            disconnect();

            return false;

        }

        return true;

    }

  private void disconnect(){

       Log.i(TAG,"disconnecting...");

         try {

                if (mSocket != null) mSocket.close();

         } catch (IOException ex) { }

         try {

                if (mIn != null) mIn.close();

         } catch (IOException ex) { }

         try {

                if (mOut != null) mOut.close();

         } catch (IOException ex) { }

         mSocket = null;

         mIn = null;

         mOut = null;

  }

private boolean readBytes(byte buffer[], int len)

private boolean writeCommand(String _cmd)

private synchronizedString transaction(String cmd)

private int execute(String cmd) {

         String res = transaction(cmd);

         try {

                return Integer.parseInt(res);

         } catch (NumberFormatException ex) {

                return -1;

         }

  }

    public int install(String name, int uid, int gid) {

        StringBuilder builder = newStringBuilder("install");

        builder.append(' ');

        builder.append(name);

        builder.append(' ');

        builder.append(uid);

        builder.append(' ');

        builder.append(gid);

        return execute(builder.toString());

    }

public int freeCache(long freeStorageSize) {

        StringBuilder builder = newStringBuilder("freecache");

        builder.append(' ');

       builder.append(String.valueOf(freeStorageSize));

        return execute(builder.toString());

    }

public int getSizeInfo(String pkgName, StringapkPath,

            String fwdLockApkPath, PackageStatspStats) {

        StringBuilder builder = newStringBuilder("getsize");

        builder.append(' ');

        builder.append(pkgName);

        builder.append(' ');

        builder.append(apkPath);

        builder.append(' ');

        builder.append(fwdLockApkPath != null ?fwdLockApkPath : "!");

        String s =transaction(builder.toString());

        String res[] = s.split(" ");

        if((res == null) || (res.length != 4)){

            return -1;

        }

        try {

            pStats.codeSize =Long.parseLong(res[1]);

            pStats.dataSize =Long.parseLong(res[2]);

            pStats.cacheSize =Long.parseLong(res[3]);

            return Integer.parseInt(res[0]);

        } catch (NumberFormatException e) {

            return -1;

        }

    }   

分析:

1) 在connect函數中,與它進行socket連接配接的是installd。Installd是android中的守護程序,用ps可以看到它,它的父程序是init,關于Android啟動流程的更加詳細的說明,請看下面這篇文章:

http://blog.csdn.net/liranke/article/details/4694989。

2) 有一些read,write函數,當然是用于對socket讀取寫資料;

3) install, freeCache, getSizeInfo隻是将固定字元串的指令傳入到execute函數中;

4) execute的實作,隻是将指令字元串通過transaction傳下去,而在中會調用writeCommand,去真正地将指令寫入到與之連接配接好的守護程序Installd。

這下,好象理清一些了:

PackageManager------aidl------- > PackageManagerService的Installer ----socket--------> Installd(c程式)。

4. Installd:這是一個用c寫成的帶有main函數的守護程序,在開機之後由init.rc調用,代碼位于:framworks/base/cmds/installd目錄下。其中,最後一個字母d,代碼的就是“dameon”,事實上,在android中,定義了好多這樣的守護程序,正是由于它們的存在,android系統才能夠正常運轉起來,也正是由于整個系統中,像這種實作方式是android中到處可以看見的。關于Installd,給出一些可以想像得到的有趣的代碼片段,有興趣的讀者,可以自己去看源碼。

Installd.c:

struct cmdinfo cmds[] ={

    { "ping",                 0, do_ping },

    { "install",             3, do_install },

    { "dexopt",               3, do_dexopt },

    { "movedex",              2, do_move_dex },

    { "rmdex",                1, do_rm_dex },

    { "remove",               1, do_remove },

    { "freecache",           1, do_free_cache },

    { "rmcache",              1, do_rm_cache },

    { "protect",              2, do_protect },

    { "getsize",             3, do_get_size },

    { "rmuserdata",           1, do_rm_user_data },

};

哦,這不就是從PackageManagerService的Installer 傳遞過來的指令字元串麼,那麼,還能想到什麼呢?

祝閱讀此文的朋友在android上描繪出精彩的一筆。

繼續閱讀