?android提供了low memory killer的机制在内存不足时回收内存。
?lmk 使用adj的方式判断该回收哪些进程或资源
android 修改adj的方法
先说结论:
A native side 统一由init进程设置/proc/**/oom_score_adj
B apk 统一由AMS 计算合适的adj,再交由lmkd 设置/proc/**/oom_score_adj
1 native side-- 直接写文档/proc/**/oom_score_adj
结论:所有的native bin档都是由init进程管理,并设置adj,默认是-1000,可以在**.rc中配置
A? ? init 进程
system/core/init/init.cpp
int SecondStageMain(int argc, char** argv) {
...
// Set init and its forked children's oom_adj.
if (auto result =
WriteFile("/proc/1/oom_score_adj", StringPrintf("%d", DEFAULT_OOM_SCORE_ADJUST));
!result.ok()) {
LOG(ERROR) << "Unable to write " << DEFAULT_OOM_SCORE_ADJUST
<< " to /proc/1/oom_score_adj: " << result.error();
}
...
}
DEFAULT_OOM_SCORE_ADJUST 定义在lmkd_service.h中,值为-1000
system/core/init/lmkd_service.h
static const int MIN_OOM_SCORE_ADJUST = -1000;
static const int MAX_OOM_SCORE_ADJUST = 1000;
// service with default score is unkillable
static const int DEFAULT_OOM_SCORE_ADJUST = MIN_OOM_SCORE_ADJUST;
在环境中验证,就是-1000
console:/ # cat /proc/1/oom_score_adj -1000
B? 其他native 进程
其他得native进程也是由init进程写得/proc/**/oom_score_adj, 如下面code所示
system/core/init/service.cpp
Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
const std::vector<gid_t>& supp_gids, int namespace_flags,
const std::string& seclabel, Subcontext* subcontext_for_restart_commands,
const std::vector<std::string>& args, bool from_apex)
: ...
oom_score_adjust_(DEFAULT_OOM_SCORE_ADJUST),
...
Result<void> Service::Start() {
...
pid_t pid = -1;
if (namespaces_.flags) {
pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
} else {
pid = fork();
}
if (pid == 0) {
...
_exit(127);
}
...
if (oom_score_adjust_ != DEFAULT_OOM_SCORE_ADJUST) {
std::string oom_str = std::to_string(oom_score_adjust_);
std::string oom_file = StringPrintf("/proc/%d/oom_score_adj", pid);
if (!WriteStringToFile(oom_str, oom_file)) {
PLOG(ERROR) << "couldn't write oom_score_adj";
}
}
...
}
该adj设置为oom_score_adjust_,默认值为DEFAULT_OOM_SCORE_ADJUST,是否可以自己配置吗?
答案是可以的
在init 中可以搜到如下code,?oom_score_adjust_是从rc档中parse出来的。
system/core/init/service_parser.cpp
Result<void> ServiceParser::ParseOomScoreAdjust(std::vector<std::string>&& args) {
if (!ParseInt(args[1], &service_->oom_score_adjust_, MIN_OOM_SCORE_ADJUST,
MAX_OOM_SCORE_ADJUST)) {
return Error() << "oom_score_adjust value must be in range " << MIN_OOM_SCORE_ADJUST
<< " - +" << MAX_OOM_SCORE_ADJUST;
}
return {};
}
const KeywordMap<ServiceParser::OptionParser>& ServiceParser::GetParserMap() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
// clang-format off
static const KeywordMap<ServiceParser::OptionParser> parser_map = {
...
{"oom_score_adjust", {1, 1, &ServiceParser::ParseOomScoreAdjust}},
...
}
}
从map的key value属性中可以看到,ParseOomScoreAdjust方法是对应的rc中的值为oom_score_adjust。没有设置的话,就是默认的-1000。
这样我们搜索oom_score_adjust定义的rc,就可以看到system/logging/logcat/logcatd.rc
这边定义的值是-600
# logcatd service service logcatd /system/bin/logcatd -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r ${logd.logpersistd.rotate_kbytes:-2048} -n ${logd.logpersistd.size:-256} --id=${ro.build.id} ? ? class late_start ? ? disabled ? ? # logd for write to /data/misc/logd, log group for read from log daemon ? ? user logd ? ? group log ? ? writepid /dev/cpuset/system-background/tasks ? ? oom_score_adjust -600
查找rc的指导文件system/core/init/README.md?
`oom_score_adjust <value>` > Sets the child's /proc/self/oom\_score\_adj to the specified value, ? which must range from -1000 to 1000.
2 apk 的adj值
apk 的adj值是根据AMS计算出来的。
在updateOomAdjLSP 会有很多的case,根据4大组件Activity, Service, Content Provider and Broadcast Receive。
具体的工作原理可以参考google 源码中的文档说明
frameworks/base/services/core/java/com/android/server/am/OomAdjuster.md
其中计算分数的说明部分,有很多的影响因子
* 如果不允许低于`ProcessList#FOREGROUND_APP_ADJ`,这意味着它可能是一个持久的进程,这里没有太多可做的。 * 检查进程是否为顶层应用,运行远程动画,运行检测,接收广播,执行服务,运行在顶层但睡眠(屏幕关闭),更新中间值。 * 询问窗口管理器(是的,ActivityTaskManager 现在与 WindowManager 一起)告诉每个活动的可见性信息。 * 检查进程是否有最近的任务,检查它是否正在托管前台服务、覆盖 UI、吐司等。 前台服务的注意事项,如果它处于前台状态,让它在内存中保持较高的等级一段时间:假设一个相机捕获案例,其中相机应用程序在切换出前景时仍在处理图片 - 保持它在内存中保持较高的等级将确保图片正确保留。 * 检查进程是否为重量级进程,其启动/退出会很慢,最好将其保存在内存中。请注意,整个系统中应该只有一个重量级进程。 * 当然,也不应该经常删除 Home 进程。 * 接下来的两个因素:对用户具有可见 UI 的前一个进程,或者是备份代理。 * 然后大量搜索连接服务service connection和内容提供商content provider,将对每个客户端进行评估,并且可以根据其客户端的分数更新自己 Oom Adj 分数。
所以最后一部分可以灵活调整apk的adj值了,
举一个例子将apk的adj设置为100
apk 调整adj的逻辑flow如下
frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java
frameworks/base/services/core/java/com/android/server/am/ProcessList.java
OomAdjuster.updateOomAdjLSP
????????OomAdjuster.updateOomAdjLSP
????????OomAdjuster.performUpdateOomAdjLSP
????????????????OomAdjuster.applyOomAdjLSP
????????????????????????ProcessList.setOomAdj
????????????????????????????????ProcessList.writeLmkd
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?LmkdConnection.exchange
????????????????????????????????????????????????LmkdConnection.write
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 通过socket 传递给lmkd
? ?lmkd 如下code中设置了/proc/%d/oom_score_adj
static void cmd_procprio(LMKD_CTRL_PACKET packet, int field_count, struct ucred *cred) {
...
/* gid containing AID_READPROC required */
/* CAP_SYS_RESOURCE required */
/* CAP_DAC_OVERRIDE required */
snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", params.pid);
snprintf(val, sizeof(val), "%d", params.oomadj);
if (!writefilestring(path, val, false)) {
ALOGW("Failed to open %s; errno=%d: process %d might have been killed",
path, errno, params.pid);
/* If this file does not exist the process is dead. */
return;
}
...
}
|