进行例如以下操作:

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

会到达例如以下界面:

能够看到这个应用占用的磁盘空间。

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

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

  • /data/data/com.myapp/lib,即so库文件夹大小
  • /data/app/com.myapp-1.apk,原始apk文件的复制
  • /data/dalvik-cache/data@app@com.myapp-1.apk@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语法,可用keyword“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的方式来通信。

->

查找文件内容。keyword为 "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语言。那可能是把函数分离实现。

所以在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://androidxref.com/

转载请注明出处:http://blog.csdn.net/hursing

Android系统应用信息中存储和缓存的计算方法的更多相关文章

  1. 如何扫描出Android系统媒体库中视频文件

    Android系统启动时会去扫描系统文件,并将系统支持的视频文件(mp4,3gp,wmv)扫描到媒体库(MediaStore)中,下面代码演示如何获得这些文件的信息: publicstatic Lis ...

  2. 获取Android系统应用信息

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...

  3. Confluence 6 系统运行信息中的 JVM 内存使用情况

    当前一个正在运行的 Confluence 6 实例的内存使用情况 https://www.cwiki.us/display/CONF6ZH/Viewing+System+Information

  4. Android 系统属性-SystemProperties详解***

    创建与修改android属性用Systemproperties.set(name, value),获取android属性用Systemproperties.get(name),需要注意的是androi ...

  5. Android系统编程入门系列之加载服务Service

    之前几篇文章简单梳理了在Android系统的四大组件之一,最主要的界面Activity中,使应用程序与用户进行交互响应的相关知识点,那对于应用程序中不需要与用户交互的逻辑,又要用到哪些内容呢?本文开始 ...

  6. Oracle性能分析11:系统统计信息

    早期Oracle查询优化器的开销计算是基于运行SQL语句所须要的物理读,这种方法被叫做I/O开销模式(I/O cost model),这种方法的主要缺点是觉得单块读和多块读开销相当.在Oracle 8 ...

  7. 第一章 Android系统移植与驱动开发概述

    本书第一章首先简单概要地介绍了关于Android系统移植和驱动开发的相关内容. 所谓“移植”是指为特定的自己的设备,如手机定制Android的过程.自己开发一些程序(移植)装载在设备上,使得Andro ...

  8. 将Android系统源码导入ecplise

    Android系统源码中带有个IDE的配置文件,目录为:development/ide/ 如果要用eclipse导入查看系统源码,则将development/ide/eclipse/.classpat ...

  9. [置顶] Android系统五大布局详解Layout

    我们知道Android系统应用程序一般是由多个Activity组成,而这些Activity以视图的形式展现在我们面前,视图都是由一个一个的组件构成的.组件就是我们常见的Button.TextEdit等 ...

随机推荐

  1. 关于comparator接口和comparable接口以及它们各自的方法compare()和compareTo()

    在今天做的LeetCode的题中有两道都出现了利用接口实现对象的排序.两题的相关链接: 1.利用comparable接口对对象排序 2.利用comparator接口实现排序 因为之前都没接触过这两个接 ...

  2. Basic Messager

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. [Android Studio] Android Studio如何提示函数用法

    Eclipse有一个很好的功能,就是当你代码调用某个android API时,鼠标移到对应的函数或者方法上,就会自动有一个悬 浮窗提示该函数的说明(所包含的参数含义,该方法功能).迁移到Android ...

  4. Spring+Mybatis+SpringMVC后台与前台分页展示实例(附工程)

    林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 摘要:本文实现了一个后台由Spring+Mybatis+SpringMVC组成,分页采用Pag ...

  5. 卷积神经网络CNN 手写数字识别

    1. 知识点准备 在了解 CNN 网络神经之前有两个概念要理解,第一是二维图像上卷积的概念,第二是 pooling 的概念. a. 卷积 关于卷积的概念和细节可以参考这里,卷积运算有两个非常重要特性, ...

  6. Informatica 常用组件Source Qualifier之二 默认查询

    2 默认查询 对于关系源,PowerCenter Server 将在运行会话时为每个源限定符转换生成查询.对于每个在映射中使用的源列,默认查询均为 SELECT 语句.也就是说,PowerCenter ...

  7. 在css加载完毕后执行后续代码

    最近在写项目的framework,写个JQueryMessageBox的类,以使用jquery ui中的dialog()来显示消息框,为了使方法方便调用,便加入了自动判断页面是否加入了ui.js和ui ...

  8. easyui更换主题之后出现validatebox的验证提示信息显示跑偏的解决方案

    在easyui中更换主题为非default的主题,有的主题会出现如下图所示的情况,验证提示信息的提示内容跑到了下面. 现在说下原因和解决方案: 原因:原因是easyui对某些主题没有进行这个样式的设置 ...

  9. 基于Spring Boot和Spring Cloud实现微服务架构学习--转

    原文地址:http://blog.csdn.net/enweitech/article/details/52582918 看了几周spring相关框架的书籍和官方demo,是时候开始总结下这中间的学习 ...

  10. Tensorflow 深度学习简介(自用)

    一些废话,也可能不是废话.可能对,也可能不对. 机器学习的定义:如果一个程序可以在任务T上,随着经验E的增加,效果P也可以随之增加,则称这个程序可以在经验中学习. “程序”指的是需要用到的机器学习算法 ...