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

來源:互聯網
上載者:User

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

一。PackageManager

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

1.PackageManager類:

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

定義: publicabstract class PackageManager {


// @hide

public abstract voidclearApplicationUserData(StringpackageName,

IPackageDataObserver observer);

// @hide

public abstract void getPackageSizeInfo(String packageName,
IPackageStatsObserver observer);

public voidinstallPackage(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中,而它的定義如下

classPackageManagerService extends IPackageManager.Stub {

finalInstaller mInstaller; //非常重要

。。。

getPackageSizeInfo(。。。)

。。。},

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

2. getPackageSizeInfo函數

public voidgetPackageSizeInfo(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);

mInstallerInstaller類型的一個執行個體,事實上,它是與android中的守護進程installd進行通訊的,通過socket.

3. Installer的定義如下:

classInstaller {

private static final String TAG ="Installer";

InputStream mIn;

OutputStream mOut;

LocalSocket mSocket;

byte buf[] = new byte[1024];

int buflen = 0;

private booleanconnect() {

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 voiddisconnect(){

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 booleanreadBytes(byte buffer[], int len)

private booleanwriteCommand(String _cmd)

private synchronizedStringtransaction(String cmd)

private intexecute(String cmd) {

String res =transaction(cmd);

try {

return Integer.parseInt(res);

} catch (NumberFormatException ex) {

return -1;

}

}

public intinstall(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 intfreeCache(long freeStorageSize) {

StringBuilder builder = newStringBuilder("freecache");

builder.append(' ');

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

return execute(builder.toString());

}

public intgetSizeInfo(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上描繪出精彩的一筆。


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.