Android系統應用資訊中儲存和緩衝的計算方法

來源:互聯網
上載者:User

標籤:android   儲存   緩衝   應用資訊   計算   

進行如下操作:

設定->應用->選擇一個應用->應用資訊

會到達如下介面:

可以看到這個應用佔用的磁碟空間。

先說結果,這幾項會計算哪些檔案(夾)。

1.應用,由三項相加組成

  • /data/data/com.myapp/lib,即so庫檔案夾大小
  • /data/app/com.myapp-1.apk,原始apk檔案的複製
  • /data/dalvik-cache/[email protected]@[email protected],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命令列可得到這樣的結果:

[email protected] ~/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", 注意包含雙引號

得到結果:

[email protected] ~/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語言,那可能是把函數分離實現。

所以在installd.c的目錄下,看到另一個代碼檔案裡實現了。轉載請註明出處:http://blog.csdn.net/hursing

->

frameworks/base/cmds/installd/commands.c

這裡就是計算的源碼了。

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){    DIR *d;    int dfd;    struct dirent *de;    struct stat s;    char path[PKG_PATH_MAX];    int64_t codesize = 0;    int64_t datasize = 0;    int64_t cachesize = 0;    int64_t asecsize = 0;        /* count the source apk as code -- but only if it's not         * on the /system partition and its not on the sdcard.         */    if (validate_system_app_path(apkpath) &&            strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {        if (stat(apkpath, &s) == 0) {            codesize += stat_size(&s);        }    }        /* count the forward locked apk as code if it is given         */    if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {        if (stat(fwdlock_apkpath, &s) == 0) {            codesize += stat_size(&s);        }    }        /* count the cached dexfile as code */    if (!create_cache_path(path, apkpath)) {        if (stat(path, &s) == 0) {            codesize += stat_size(&s);        }    }        /* add in size of any libraries */    if (!create_pkg_path_in_dir(path, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) {        d = opendir(path);        if (d != NULL) {            dfd = dirfd(d);            codesize += calculate_dir_size(dfd);            closedir(d);        }    }        /* compute asec size if it is given         */    if (asecpath != NULL && asecpath[0] != '!') {        if (stat(asecpath, &s) == 0) {            asecsize += stat_size(&s);        }    }    if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, persona)) {        goto done;    }    d = opendir(path);    if (d == NULL) {        goto done;    }    dfd = dirfd(d);    /* most stuff in the pkgdir is data, except for the "cache"     * directory and below, which is cache, and the "lib" directory     * and below, which is code...     */    while ((de = readdir(d))) {        const char *name = de->d_name;        if (de->d_type == DT_DIR) {            int subfd;            int64_t statsize = 0;            int64_t dirsize = 0;                /* always skip "." and ".." */            if (name[0] == '.') {                if (name[1] == 0) continue;                if ((name[1] == '.') && (name[2] == 0)) continue;            }            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {                statsize = stat_size(&s);            }            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);            if (subfd >= 0) {                dirsize = calculate_dir_size(subfd);            }            if(!strcmp(name,"lib")) {                codesize += dirsize + statsize;            } else if(!strcmp(name,"cache")) {                cachesize += dirsize + statsize;            } else {                datasize += dirsize + statsize;            }        } else if (de->d_type == DT_LNK && !strcmp(name,"lib")) {            // This is the symbolic link to the application's library            // code.  We'll count this as code instead of data, since            // it is not something that the app creates.            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {                codesize += stat_size(&s);            }        } else {            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {                datasize += stat_size(&s);            }        }    }    closedir(d);done:    *_codesize = codesize;    *_datasize = datasize;    *_cachesize = cachesize;    *_asecsize = asecsize;    return 0;}
以上是計算了內部磁碟的佔用,還不齊,還有線索:

PackageManagerService.java的內部類MeasureParams.handleStartCopy()函數:

void handleStartCopy() throws RemoteException {            synchronized (mInstallLock) {                mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats.userHandle, mStats);            }            final boolean mounted;            if (Environment.isExternalStorageEmulated()) {                mounted = true;            } else {                final String status = Environment.getExternalStorageState();                mounted = (Environment.MEDIA_MOUNTED.equals(status)                        || Environment.MEDIA_MOUNTED_READ_ONLY.equals(status));            }            if (mounted) {                final UserEnvironment userEnv = new UserEnvironment(mStats.userHandle);                final File externalCacheDir = userEnv                        .getExternalStorageAppCacheDirectory(mStats.packageName);                final long externalCacheSize = mContainerService                        .calculateDirectorySize(externalCacheDir.getPath());                mStats.externalCacheSize = externalCacheSize;                final File externalDataDir = userEnv                        .getExternalStorageAppDataDirectory(mStats.packageName);                long externalDataSize = mContainerService.calculateDirectorySize(externalDataDir                        .getPath());                if (externalCacheDir.getParentFile().equals(externalDataDir)) {                    externalDataSize -= externalCacheSize;                }                mStats.externalDataSize = externalDataSize;                final File externalMediaDir = userEnv                        .getExternalStorageAppMediaDirectory(mStats.packageName);                mStats.externalMediaSize = mContainerService                        .calculateDirectorySize(externalMediaDir.getPath());                final File externalObbDir = userEnv                        .getExternalStorageAppObbDirectory(mStats.packageName);                mStats.externalObbSize = mContainerService.calculateDirectorySize(externalObbDir                        .getPath());            }        }
這裡計算了sd卡上的磁碟佔用。


內部磁碟的計算,是用linux的stat函數。

一些目錄和檔案的常量,定義在installd.h

認真看代碼,則會得到文章開頭的結果。

代碼計算的結果得到的是佔用磁碟的大小,但由於儲存空間有"4K對齊”的概念,所以佔用磁碟大小不等於檔案大小。例如一個實際為2.98K的檔案,會在應用資訊裡顯示為4K。


轉載請註明出處:http://blog.csdn.net/hursing

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.