android缓存垃圾扫描功能吗,Android 系统缓存扫描与清理方法分析

本文深入分析了Android系统中如何计算和清理应用缓存。从设置应用的源码出发,揭示了缓存大小计算的过程,涉及内部缓存和外部缓存的路径。同时讨论了权限限制对清理缓存的影响,并提供了具有root权限时的缓存管理思路。
摘要由CSDN通过智能技术生成

我们先来看一个熟悉的界面:

2f401dd88819cafa8da81650718dbf3a.png

这是手机的「设置」——「应用」里的已安装应用的详情页,这里面会显示缓存的大小,而且提供了清理缓存的功能,这就是我们做「系统缓存」清理想做的事情。

这里显示的大小是如何计算出来的,它实际上的文件组成是怎么样的呢?可以从 Android 系统自带的 Settings APP 的源码中找到答案。

注:下面的分析基于Android 4.1 源码,比较古老了,但并不妨碍理解。

探索「外部缓存」

按惯例先说结论:

「外部缓存」由所有已安装应用的 /sdcard/Android/data/packagename/cache 文件夹组成。

Settings APP 的源码在 Android 源码树的 packages/apps/Settings 目录里,在它里面能找到 InstalledAppDetails.java 文件,从名字上看它应该就是对应我们上图中的「应用详情页」,它是一个 Fragment,在它的onResume方法中调用了refreshUi方法,它里面又调用了refreshSizeInfo方法:

private void refreshSizeInfo() {

if (mAppEntry.size == ApplicationsState.SIZE_INVALID

|| mAppEntry.size == ApplicationsState.SIZE_UNKNOWN) {

......

} else {

......

long cacheSize = mAppEntry.cacheSize + mAppEntry.externalCacheSize;

if (mLastCacheSize != cacheSize) {

mLastCacheSize = cacheSize;

mCacheSize.setText(getSizeStr(cacheSize));

}

......

}

}

这个方法定义在文件 packages/apps/Settings/src/com/android/settings/applications/InstalledAppDetails.java 中。

很显然这里的cacheSize就是对应上图里的缓存大小,从这几行代码的字面意义里可以看出缓存是由「内部缓存」加「外部缓存」组成,甚至可以初步推测出本节的结论,当然这里要继续深究一下其中的原理。

找到给mAppEntry赋值的地方:

private boolean refreshUi() {

......

mAppEntry = mState.getEntry(packageName);

......

}

这个方法定义在文件 packages/apps/Settings/src/com/android/settings/applications/InstalledAppDetails.java 中。

继续看getEntry里做了什么:

AppEntry getEntry(String packageName) {

......

for (int i=0; i

ApplicationInfo info = mApplications.get(i);

if (packageName.equals(info.packageName)) {

entry = getEntryLocked(info);

break;

}

}

.......

}

这个方法定义在文件 packages/apps/Settings/src/com/android/settings/applications/ApplicationsState.java 中。

找到给mApplications添加数据的地方:

void addPackage(String pkgName) {

try {

synchronized (mEntriesMap) {

......

ApplicationInfo info = mPm.getApplicationInfo(pkgName,

PackageManager.GET_UNINSTALLED_PACKAGES |

PackageManager.GET_DISABLED_COMPONENTS);

mApplications.add(info);

if (!mBackgroundHandler.hasMessages(BackgroundHandler.MSG_LOAD_ENTRIES)) {

mBackgroundHandler.sendEmptyMessage(BackgroundHandler.MSG_LOAD_ENTRIES);

}

......

}

} catch (NameNotFoundException e) {

}

}

这个方法定义在文件 packages/apps/Settings/src/com/android/settings/applications/ApplicationsState.java 中。

它在mApplications.add(info);后顺便发了个消息,经过MSG_LOAD_ENTRIES到MSG_LOAD_ICONS到MSG_LOAD_SIZES的消息链,我们看到一个从名字上就看出来很重要的关键方法调用getPackageSizeInfo:

class BackgroundHandler extends Handler {

......

@Override

public void handleMessage(Message msg) {

......

switch (msg.what) {

......

case MSG_LOAD_ENTRIES: {

......

if (numDone >= 6) {

......

} else {

sendEmptyMessage(MSG_LOAD_ICONS);

}

} break;

case MSG_LOAD_ICONS: {

......

if (numDone >= 2) {

......

} else {

sendEmptyMessage(MSG_LOAD_SIZES);

}

} break;

case MSG_LOAD_SIZES: {

synchronized (mEntriesMap) {

......

mPm.getPackageSizeInfo(mCurComputingSizePkg, mStatsObserver);

......

}

} break;

}

}

......

}

这个类定义在文件 packages/apps/Settings/src/com/android/settings/applications/ApplicationsState.java 中。

mPm是PackageManager类型的,这是一个抽象类型,它的实现类为ApplicationPackageManager,ApplicationPackageManager.getPackageSizeInfo里调用了IPackageManager.getPackageSizeInfo,IPackageManager的实例在ContexImpl.getPackageManager方法里通过ActivityThread.getPackageManager()获得,它的方法调用最终是反映到通过 Binder 机制返回的PackageManagerService实例上,我们找到getPackageSizeInfo的最终实现:

public class PackageManagerService extends IPackageManager.Stub {

......

public void getPackageSizeInfo(final String packageName,

final IPackageStatsObserver observer) {

......

Message msg = mHandler.obtainMessage(INIT_COPY);

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

mHandler.sendMessage(msg);

}

......

}

这个方法定义在文件 frameworks/base/services/java/com/android/server/pm/PackageManagerService.java 中。

这里我们注意msg.obj的类型为MeasureParams,INIT_COPY消息对应的处理:

class PackageHandler extends Handler {

private boolean mBound = false;

......

public void handleMessage(Message msg) {

......

doHandleMessage(msg);

......

}

void doHandleMessage(Message msg) {

switch (msg.what) {

case INIT_COPY: {

......

if (!mBound) {

if (!connectToService()) {

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值