編輯:關於Android編程
進行如下操作:
設置->應用->選擇一個應用->應用信息
會到達如下界面:
可以看到這個應用占用的磁盤空間。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+z8jLtb3hufujrNXivLjP7rvhvMbL48TE0KnOxLz+o6i80KOpoaM8L3A+CjxwPjxzdHJvbmc+MS7TptPDPC9zdHJvbmc+o6zTycj9z+7P4LzT1+mzyTwvcD4KPHA+PC9wPgoKL2RhdGEvZGF0YS9jb20ubXlhcHAvbGlio6y8tHNvv+LOxLz+vNC089ChL2RhdGEvYXBwL2NvbS5teWFwcC0xLmFwa6Os1K3KvGFwa87EvP61xLi01sYvZGF0YS9kYWx2aWstY2FjaGUvZGF0YUBhcHBAY29tLm15YXBwLTEuYXBrQGNsYXNzZXMuZGV4o6xkYWx2aWvQ6cTiu/q21GRleM7EvP61xLu6tOYKPHA+PC9wPgo8cD48c3Ryb25nPjIuVVNCtOa0oqOo06bTw6OpPC9zdHJvbmc+oaOw0bPM0PLXsLW9o6i78tLGtb2jqXNkv6i687XEtPPQoaGjL3NkY2FyZC9BbmRyb2lkLy4uLqOsss6/vKGw06bTw6Gxz+6hozwvcD4KPHA+PHN0cm9uZz4zLsr9vt08L3N0cm9uZz4gPSAvZGF0YS9kYXRhL2NvbS5teWFwcC/Ev8K8tPPQoSAtIGNhY2hl19PEv8K8tPPQoSAtIGxpYtfTxL/CvLTz0KE8L3A+CjxwPjxzdHJvbmc+NC5TRCC/qDwvc3Ryb25nPiA9IC9zZGNhcmQvQW5kcm9pZC9kYXRhL2NvbS5teWFwcC/Ev8K8tPPQoSAtIC9zZGNhcmQvQW5kcm9pZC9kYXRhL2NvbS5teWFwcC9jYWNoZcS/wry089ChPC9wPgo8cD6jqDxzdHJvbmc+19y8xjwvc3Ryb25nPsrH0tTJzzS49tauus2jqTwvcD4KPHA+PHN0cm9uZz41Lru6tOY8L3N0cm9uZz4gPSAvZGF0YS9kYXRhL2NvbS5teWFwcC9jYWNoZcS/wry089ChICYjNDM7IC9zZGNhcmQvQW5kcm9pZC9kYXRhL2NvbS5teWFwcC9jYWNoZcS/wry089ChPC9wPgo8cD48YnI+CjwvcD4KPHA+z8LD5srHt9bO9kFuZHJvaWQ0LjLUtMLr1PXDtNf2tcSho7HIvc/P6s+4y7W31s72uf2zzKOsu+HA29e40KmjrMra1q7S1NPmsMmhozwvcD4KPHA+uPm+3dOm08PQxc+itcS958PmU2V0dGluZ3PV4rj2w/vX1qOsssKy4rW91LTC6zwvcD4KPHA+YW5kcm9pZDQuMi9wYWNrYWdlcy9hcHBzL1NldHRpbmdzL3NyYy9jb20vYW5kcm9pZC9zZXR0aW5ncy9hcHBsaWNhdGlvbnMvSW5zdGFsbGVkQXBwRGV0YWlscy5qYXZhPC9wPgo8cD64utTwo6y21NOmtcR4bWzKxzwvcD4KPHA+YW5kcm9pZDQuMi9wYWNrYWdlcy9hcHBzL1NldHRpbmdzL3Jlcy9sYXlvdXQvaW5zdGFsbGVkX2FwcF9kZXRhaWxzLnhtbDxicj4KPC9wPgo8cD7LotDCtMXFzNW808O089ChtcS6r8r9ysc8L3A+CjxwPkluc3RhbGxlZEFwcERldGFpbGVkcy5yZWZyZXNoU2l6ZUluZm8oKTwvcD4KPHA+uPm+3bT6wuvP38v3t7Sy6TwvcD4KPHA+bURhdGFTaXplLnNldFRleHQoZ2V0U2l6ZVN0cihkYXRhU2l6ZSkpOzwvcD4KPHA+LT48L3A+CjxwPmxvbmcgZGF0YVNpemUgPSBtQXBwRW50cnkuZGF0YVNpemU7PGJyPgo8L3A+CjxwPi0+PC9wPgo8cD5tQXBwRW50cnkgPSBtU3RhdGUuZ2V0RW50cnkocGFja2FnZU5hbWUpOzxicj4KPC9wPgo8cD4tPjwvcD4KPHA+bVN0YXRlLnJlcXVlc3RTaXplKG1BcHBFbnRyeS5pbmZvLnBhY2thZ2VOYW1lKTs8YnI+CjwvcD4KPHA+QXBwbGljYXRpb25zU3RhdGUgbVN0YXRlPGJyPgo8L3A+CjxwPi0+PC9wPgo8cD5hbmRyb2lkNC4yL3BhY2thZ2VzL2FwcHMvU2V0dGluZ3Mvc3JjL2NvbS9hbmRyb2lkL3NldHRpbmdzL2FwcGxpY2F0aW9ucy9BcHBsaWNhdGlvblN0YXRlLmphdmE8YnI+CjwvcD4KPHA+bVBtLmdldFBhY2thZ2VTaXplSW5mbyhwYWNrYWdlTmFtZSwgbUJhY2tncm91bmRIYW5kbGVyLm1TdGF0c09ic2VydmVyKTs8YnI+CjwvcD4KPHA+ZmluYWwgUGFja2FnZU1hbmFnZXIgbVBtPGJyPgo8L3A+CjxwPi0+PC9wPgo8cD5hbmRyb2lkNC4yL2ZyYW1ld29ya3MvYmFzZS9jb3JlL2phdmEvYW5kcm9pZC9hcHAvQXBwbGljYXRpb25QYWNrYWdlTWFuYWdlci5qYXZhPGJyPgo8L3A+CjxwPnB1YmxpYyB2b2lkIGdldFBhY2thZ2VTaXplSW5mbyhTdHJpbmcgcGFja2FnZU5hbWUsIGludCB1c2VySGFuZGxlLDxicj4KICAgICAgICAgICAgSVBhY2thZ2VTdGF0c09ic2VydmVyIG9ic2VydmVyKSB7PGJyPgo8L3A+CjxwPm1QTS5nZXRQYWNrYWdlU2l6ZUluZm8ocGFja2FnZU5hbWUsIHVzZXJIYW5kbGUsIG9ic2VydmVyKTs8YnI+CjwvcD4KPHA+cHJpdmF0ZSBmaW5hbCBJUGFja2FnZU1hbmFnZXIgbVBNOzxicj4KPC9wPgo8cD4tPjwvcD4KPHA+SVBhY2thZ2VNYW5hZ2Vyyse49r3Tv9qjrNPDsunV0s7EvP7E2sjdtcS3vcq9y9HL98v8tcTKtc/Wo6y4+b7damF2YdPvt6ijrL/J08O52Lz819ahsGV4dGVuZHMgSVBhY2thZ2VNYW5hZ2VyobE8YnI+CjwvcD4KPHA+08NzaGVsbMP8we7Q0L/JtcO1vdXi0fm1xL3hufujujwvcD4KPHA+bGl1aHhAdWMgfi9EZXNrdG9wL2FuZHJvaWQ0LjIgJCBncmVwIC1ybnN3IA=="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:
sdk/files/ant/build.xml:1392:
->
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
0x00我們首先講一個webView這個方法的作用:webView.getSettings().setAllowFileAccessFromFileURLs(false)
在前面一篇文章中,我們分析了Android模塊的編譯過程。當Android系統的所有模塊都編譯好之後,我們就可以對編譯出來的模塊文件進行打包了。打包結果是獲得一系列的鏡像
寫這篇博客的目的就是教大家利用AndroidSDK自帶的support lib來實現APP日間/夜間模式的切換,最近看到好多帖子在做關於這個日夜間模式切換的開源項目,其實
下面我們把這個控件內嵌到Layout中做一些動畫和展示,效果圖: 這個子控件可以上下移動,可以左右滑動,如果上下滑動距離大於左右滑動距離,則必須上下滑動 @Ove