天天看点

Android系统应用信息中存储和缓存的计算方法

进行如下操作:

设置->应用->选择一个应用->应用信息

会到达如下界面:

可以看到这个应用占用的磁盘空间。

先说结果,这几项会计算哪些文件(夹)。

1.应用,由三项相加组成

/data/data/com.myapp/lib,即so库文件夹大小

/data/app/com.myapp-1.apk,原始apk文件的复制

/data/dalvik-cache/data@[email protected]@classes.dex,dalvik虚拟机对dex文件的缓存

2.USB存储(应用)。把程序装到(或移到)sd卡后的大小。/sdcard/Android/...,参考“应用”项。

3.数据 = /data/data/com.myapp/目录大小 - cache子目录大小 - lib子目录大小

4.SD 卡 = /sdcard/Android/data/com.myapp/目录大小 - /sdcard/Android/data/com.myapp/cache目录大小

(总计是以上4个之和)

5.缓存 = /data/data/com.myapp/cache目录大小 + /sdcard/Android/data/com.myapp/cache目录大小

下面是分析Android4.2源码怎么做的。比较详细说分析过程,会累赘些,授之以渔吧。

根据应用信息的界面Settings这个名字,猜测到源码

android4.2/packages/apps/Settings/src/com/android/settings/applications/InstalledAppDetails.java

负责,对应的xml是

android4.2/packages/apps/Settings/res/layout/installed_app_details.xml

刷新磁盘占用大小的函数是

InstalledAppDetaileds.refreshSizeInfo()

根据代码线索反查

mDataSize.setText(getSizeStr(dataSize));

->

long dataSize = mAppEntry.dataSize;

mAppEntry = mState.getEntry(packageName);

mState.requestSize(mAppEntry.info.packageName);

ApplicationsState mState

android4.2/packages/apps/Settings/src/com/android/settings/applications/ApplicationState.java

mPm.getPackageSizeInfo(packageName, mBackgroundHandler.mStatsObserver);

final PackageManager mPm

android4.2/frameworks/base/core/java/android/app/ApplicationPackageManager.java

public void getPackageSizeInfo(String packageName, int userHandle,

            IPackageStatsObserver observer) {

mPM.getPackageSizeInfo(packageName, userHandle, observer);

private final IPackageManager mPM;

IPackageManager是个接口,用查找文件内容的方式搜索它的实现,根据java语法,可用关键字“extends IPackageManager”

用shell命令行可得到这样的结果:

liuhx@uc ~/Desktop/android4.2 $ grep -rnsw "extends IPackageManager" *

frameworks/base/services/java/com/android/server/pm/PackageManagerService.java:172:public class PackageManagerService extends IPackageManager.Stub {

android4.2/frameworks/base/services/java/com/android/server/pm/PackageManagerService.java

public void getPackageSizeInfo(

Message msg = mHandler.obtainMessage(INIT_COPY);

        msg.obj = new MeasureParams(stats, observer);

        mHandler.sendMessage(msg);

内部类class MeasureParams

void handleStartCopy() throws RemoteException {

mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats.userHandle, mStats);

getPackageSizeInfoLI函数

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

                asecPath, pStats);

final Installer mInstaller

frameworks/base/services/java/com/android/server/pm/Installer.java

public int getSizeInfo(

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

 private synchronized String transaction(String cmd) {

if (!writeCommand(cmd)) {

private boolean writeCommand(String _cmd)

mOut.write(buf, 0, 2);

mOut.write(cmd, 0, len);

OutputStream mOut;

LocalSocketAddress address = new LocalSocketAddress("installd",

                    LocalSocketAddress.Namespace.RESERVED);

            mSocket.connect(address);

            mOut = mSocket.getOutputStream();

到此很无语,用socket的方式来通信。

查找文件内容,关键字为 "installd", 注意包含双引号

得到结果:

liuhx@uc ~/Desktop/android4.2 $ grep -rnsw "\"installd\"" *

cts/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/RootProcessScanner.java:33:            "installd",

frameworks/base/services/java/com/android/server/pm/Installer.java:51:            LocalSocketAddress address = new LocalSocketAddress("installd",

frameworks/base/cmds/installd/installd.h:18:#define LOG_TAG "installd"

frameworks/base/cmds/installd/installd.h:49:#define SOCKET_PATH "installd"

sdk/files/ant/build.xml:1355:                                    <condition property="tested.project.install.target" value="installi" else="installd">

sdk/files/ant/build.xml:1392:    <target name="installd" depends="-set-debug-files, install"

frameworks/base/cmds/installd/installd.h

int get_size(const char *pkgname, int persona, const char *apkpath, const char *fwdlock_apkpath,

             const char *asecpath, int64_t *codesize, int64_t *datasize, int64_t *cachesize,

             int64_t *asecsize);

frameworks/base/cmds/installd/installd.c

static int do_get_size(char **arg, char reply[REPLY_MAX])

res = get_size(arg[0], atoi(arg[1]), arg[2], arg[3], arg[4],

            &codesize, &datasize, &cachesize, &asecsize);

看到在installd.c没有实现get_size函数。可以根据函数声明搜索文件内容,不过既然是c语言,那可能是把函数分离实现。

frameworks/base/cmds/installd/commands.c

这里就是计算的源码了。

以上是计算了内部磁盘的占用,还不齐,还有线索:

PackageManagerService.java的内部类MeasureParams.handleStartCopy()函数:

这里计算了sd卡上的磁盘占用。

一些目录和文件的常量,定义在installd.h

认真看代码,则会得到文章开头的结果。

代码计算的结果得到的是占用磁盘的大小,但由于存储器有"4K对齐”的概念,所以占用磁盘大小不等于文件大小。例如一个实际为2.98K的文件,会在应用信息里显示为4K。