android 修改adj的方法

 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;
    }
    ...
}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值