AndroidDropBoxManager服务分析

更新时间:2023-07-07 19:48:54 阅读: 评论:0

AndroidDropBoxManager服务分析
⼀、启动流程
DropBoxManagerService(简称DBMS) 记录着系统关键log信息,主要功能⽤于Debug调试。 Android系统启动过程SystemServer进程时,在startOtherServices()过程会启动DBMS服务,如下:
1.1 启动DBMS
[-> SystemServer.java]
private void startOtherServices() {
//初始化DBMS,并登记该服务【见⼩节1.2】
ServiceManager.addService(Context.DROPBOX_SERVICE,
new DropBoxManagerService(context, new File(“/data/system/dropbox”)));
}
其中DROPBOX_SERVICE = “dropbox”, DBMS⼯作⽬录位于”/data/system/dropbox”,这个过程向ServiceManager 登记名
为“dropbox”的服务。那么可通过dumpsys dropbox来查看该dropbox服务信息。
1.2 初始化DBMS
[-> DropBoxManagerService.java]
public final class DropBoxManagerService extends IDropBoxManagerService.Stub {
public DropBoxManagerService(final Context context, File path) {
mDropBoxDir = path;  // ⽬录/data/system/dropbox
mContext = context;
mContentResolver = ContentResolver();
IntentFilter filter = new IntentFilter();
// 监听存储设备可⽤空间低的⼴播
风俗文化
filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
// 监听开机完毕的⼴播
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
小雨的故事
// Settings数据库变化时则回调⼴播接收者的onReceive⽅法,此处CONTENT_URI=content://ttings/global"
Settings.Global.CONTENT_URI, true,
new ContentObrver(new Handler()) {
public void onChange(boolean lfChange) {
}
});
mHandler = new Handler() {
public void handleMessage(Message msg) {
// 发送⼴播
if (msg.what == MSG_SEND_BROADCAST) {
mContext.ndBroadcastAsUr((Intent)msg.obj, UrHandle.OWNER,
android.Manifest.permission.READ_LOGS);
}
}
};
}
}
该⽅法主要功能是给dropbox⽬录所对应的存储空间进⾏瘦⾝:
存储设备可⽤空间低;
开机完毕;
Settings数据库变化;
当发⽣任⼀以上情况都会触发触发执⾏mReceiver的onReceive⽅法,接下来看看该onReceive()过程.
1.Receive
[-> DropBoxManagerService.java]
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (intent != null && Intent.ACTION_BOOT_COMPLETED.Action())) { mBooted = true;
一千的英文return;
}
//收到ACTION_DEVICE_STORAGE_LOW,则强制重新check存储空间
mCachedQuotaUptimeMillis = 0;
//创建⼯作线程来执⾏init和trim操作
new Thread() {
public void run() {
try {
init(); //【见⼩节1.3.1】
trimToFit(); //【见⼩节1.3.2】
} catch (IOException e) {
.
..
}
}
}.start();
}
};
1.3.1 init
private synchronized void init() throws IOException {
if (mStatFs == null) {
if (!mDropBoxDir.isDirectory() && !mDropBoxDir.mkdirs()) {
}
mStatFs = new Path());
mBlockSize = BlockSize(); //mBlockSize=4096
}
if (mAllFiles == null) {
File[] files = mDropBoxDir.listFiles();
// 列举所有的dropbox⽂件
mAllFiles = new FileList();
mFilesByTag = new HashMap<String, FileList>();
for (File file : files) {
if (Name().endsWith(".tmp")) {
file.delete(); //删除后缀为.tmp⽂件
continue;
}
// 创建dropbox的实体⽂件对象, 根据⽂件名来获取相应的时间戳
EntryFile entry = new EntryFile(file, mBlockSize);
if (entry.tag == null) {
continue; //忽略tag为空的⽂件
} el if (entry.timestampMillis == 0) {
file.delete(); //删除时间戳为0的⽂件
continue;
}
/
/将entry加⼊到mAllFiles对象
enrollEntry(entry);
}
}
}
该⽅法主要功能:
创建⽬录/data/system/dropbox;
列举该⽬录下所有⽂件,并对其进⾏:
将每⼀个dropbox⽂件都对应于⼀个EntryFile对象,根据⽂件名来获取相应的时间戳 删除后缀为.tmp的⽂件;
删除时间戳为0的⽂件.
1.3.2 trimToFit
private synchronized long trimToFit() {
int ageSeconds = Int(mContentResolver,
Settings.Global.DROPBOX_AGE_SECONDS, DEFAULT_AGE_SECONDS);
int maxFiles = Int(mContentResolver,
Settings.Global.DROPBOX_MAX_FILES, DEFAULT_MAX_FILES);
long cutoffMillis = System.currentTimeMillis() - ageSeconds * 1000;
while (!ts.isEmpty()) {
EntryFile entry = ts.first();
//当最⽼的⽂件时间戳在3天之内,且⽂件个数低于1000,则跳出循环
if (entry.timestampMillis > cutoffMillis
&& ts.size() < maxFiles) break;
FileList tag = (entry.tag);kpokaht
if (tag != null && ve(entry)) tag.blocks -= entry.blocks;
if (ve(entry)) mAllFiles.blocks -= entry.blocks;
if (entry.file != null) entry.file.delete(); //删除⽂件
}
long uptimeMillis = SystemClock.uptimeMillis();
//除⾮接收设备存储低的⼴播,否则间隔5s才能再次执⾏restat
if (uptimeMillis > mCachedQuotaUptimeMillis + QUOTA_RESCAN_MILLIS) {
int quotaPercent = Int(mContentResolver,
Settings.Global.DROPBOX_QUOTA_PERCENT, DEFAULT_QUOTA_PERCENT);
int rervePercent = Int(mContentResolver,
Settings.Global.DROPBOX_RESERVE_PERCENT, DEFAULT_RESERVE_PERCENT);    int quotaKb = Int(mContentResolver,
Settings.Global.DROPBOX_QUOTA_KB, DEFAULT_QUOTA_KB);
//重新统计⽂件
int available = AvailableBlocks();
int available = AvailableBlocks();
int nonrerved = available - BlockCount() * rervePercent / 100;
int maximum = quotaKb * 1024 / mBlockSize;
//可⽤的块数量
mCachedQuotaBlocks = Math.min(maximum, Math.max(0, nonrerved * quotaPercent / 100));
mCachedQuotaUptimeMillis = uptimeMillis;
}
if (mAllFiles.blocks > mCachedQuotaBlocks) {
//公平地限制所有tag的空间
int unsqueezed = mAllFiles.blocks, squeezed = 0;
TreeSet<FileList> tags = new TreeSet<FileList>(mFilesByTag.values());
for (FileList tag : tags) {
if (squeezed > 0 && tag.blocks <= (mCachedQuotaBlocks - unsqueezed) / squeezed) {
break;
}
unsqueezed -= tag.blocks;
squeezed++;
}
int tagQuota = (mCachedQuotaBlocks - unsqueezed) / squeezed;
//移除每个tags中的旧items
for (FileList tag : tags) {
if (mAllFiles.blocks < mCachedQuotaBlocks) break;
while (tag.blocks > tagQuota && !ts.isEmpty()) {
EntryFile entry = ts.first();
if (ve(entry)) tag.blocks -= entry.blocks;
if (ve(entry)) mAllFiles.blocks -= entry.blocks;
try {
if (entry.file != null) entry.file.delete();
enrollEntry(new EntryFile(mDropBoxDir, entry.tag, entry.timestampMillis));
} catch (IOException e) {来月经腰痛
Slog.e(TAG, "Can't write tombstone file", e);
}
}
蹈字组词语}
}
return mCachedQuotaBlocks * mBlockSize;
}
trimToFit过程中触发条件是:当⽂件有效时长超过3天,或者最⼤⽂件数超过1000,再或者剩余可⽤存储设备过低;DBMS有很多常量参数:
DEFAULT_AGE_SECONDS = 3 * 86400:⽂件最长可存活时长为3天
DEFAULT_MAX_FILES = 1000:最⼤dropbox⽂件个数为1000
DEFAULT_QUOTA_KB = 5 * 1024:分配dropbox空间的最⼤值5M
DEFAULT_QUOTA_PERCENT = 10:是指dropbox⽬录最多可占⽤空间⽐例10%
DEFAULT_RESERVE_PERCENT = 10:是指dropbox不可使⽤的存储空间⽐例10%
QUOTA_RESCAN_MILLIS = 5000:重新扫描retrim时长为5s
当然上⾯这些都是默认值,完全可以通过设置content://ttings/global数据库中相应项来设定值。
⼆、DropBox⼯作
当发⽣以下任⼀场景,都会调⽤AMS.addErrorToDropBox()来触发DBMS⼯作。
crash: ⽂章理解Android Crash处理流程 [⼩节4]的AMS.handleApplicationCrashInner过程 anr: ⽂章android ANR原理分析[⼩节3.1]的AMS.appNotResponding()过程;
金银花采摘机watchdog: ⽂章WatchDog⼯作原理 [⼩节3.1]的Watchdog.run()过程;
native_crash: 当调⽤NativeCrashReporter.run()的过程;
wtf: 当调⽤Log.wtf()或者Log.wtfQuiet()的过程;
lowmem: 当内存较低时,触发portMemUsage()过程;
2.1 AMS.addErrorToDropBox
[–>ActivityManagerService.java]
public void addErrorToDropBox(String eventType,
ProcessRecord process, String processName, ActivityRecord activity,
ActivityRecord parent, String subject,
final String report, final File logFile,
final ApplicationErrorReport.CrashInfo crashInfo) {
//创建dropbox标签名【见⼩节2.1.1】
final String dropboxTag = processClass(process) + "_" + eventType;
//获取dropbox服务的代理端
final DropBoxManager dbox = (DropBoxManager)
//当不需要输出dropbox报告则直接返回
if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
final StringBuilder sb = new StringBuilder(1024);
//输出Process,flags,以及进程中所有package 【见⼩节2.1.2】
appendDropBoxProcessHeaders(process, processName, sb);
...
if (subject != null) {
sb.append("Subject: ").append(subject).append("\n");
}
sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
sb.append("\n");
//创建新线程,避免将调⽤者阻塞在I/O
Thread worker = new Thread("Error dump: " + dropboxTag) {
@Override
public void run() {
if (report != null) {
//⽐如ANR时输出Cpuinfo,或者lowmem时输出的内存信息
sb.append(report);
自由潜水
}
if (logFile != null) {
//⽐如anr或者Watchdog时输出的traces⽂件(kill -3),最⼤上限为256KB
sb.adTextFile(logFile, DROPBOX_MAX_SIZE,
"\n\n[[TRUNCATED]]"));
}
if (crashInfo != null && crashInfo.stackTrace != null) {
// ⽐如crash时输出的调⽤栈
sb.append(crashInfo.stackTrace);
}
String tting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag;
int lines = ContentResolver(), tting, 0);
//当dropboxTag所对应的ttings项不等于0,则输出logcat
if (lines > 0) {
//输出evets/system/main/crash这些log信息
java.lang.Process logcat = new ProcessBuilder("/system/bin/logcat",
"-v", "time", "-b", "events", "-b", "system", "-b", "main",
"-b", "crash",
"-t", String.valueOf(lines)).redirectErrorStream(true).start();

本文发布于:2023-07-07 19:48:54,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1084180.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:服务   空间   信息   创建   存储空间
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图