需要调用getPackageSizeInfo来计算缓存大小,但PackageManager中这个方法是隐藏的,可能开发人员觉得不安全不暴露接口?用到反射的概念
Method method=MainActivity.this.getPackageManager().getClass().getMethod(..)
然后调用getPackageSizeInfo 方法
method.invoke(PackageManager(方法所在的类),String.class,IPackageStatsObserver.class(方法参数,本来以为第二个参数是自定义的,只要是实现了AIDL 接口并且继承了Binder的类就可以,然后看了getPackageSizeInfo的源码发现IPackageStatsObserver类是确定的并且有回调方法onGetStatsCompleted()但是这个方法是自定义的,所以这个IPackageStatsObserver类是什么?为啥还需要AIDL,直接继承Interface不久可以了吗?而且要将IPackageStatsObserver.aidl文件放在android.content.pm包下,aidl文件C/s端的aidl文件要有相同的包名(文件不一致会出现问题),难道是远程调用?那c/s端分别是什么?))
下面是从网上找的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 {
//回调IPackageStatsObserver的方法
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.
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, String apkPath,
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程序)。
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 传递过来的命令字符串。