2024年Android Freezer_cachedappoptimizer,2024年最新HarmonyOS鸿蒙架构师面试题

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!


img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以戳这里获取

Android Q 开始,谷歌引入了cgroup抽象层,搭配使用任务配置文件,来屏蔽底层cgroup调用细节,向上提供API。cgroup抽象层编译成库libprocessgroup。抽象层通过往cgroup的文件节点写入相应的值,来触发kernel的回调。

最终kernel cgroup机制的freezer控制子系统真正实现了冰冻进程的功能。

一个进程从前台运行到被冰冻的旅程

2 Framework 上层

2.1 代码路径及流程

frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java
frameworks/base/services/core/java/com/android/server/am/CachedAppOptimizer.java
frameworks/base/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
frameworks/base/core/java/android/os/Process.java
frameworks/base/core/jni/android_util_Process.cpp 

2.2 OomAdjuster更新进程adj的场景

 static final String OOM_ADJ_REASON_NONE = OOM_ADJ_REASON_METHOD + "_meh";
 static final String OOM_ADJ_REASON_ACTIVITY = OOM_ADJ_REASON_METHOD + "_activityChange";
 static final String OOM_ADJ_REASON_FINISH_RECEIVER = OOM_ADJ_REASON_METHOD + "_finishReceiver";
 static final String OOM_ADJ_REASON_START_RECEIVER = OOM_ADJ_REASON_METHOD + "_startReceiver";
 static final String OOM_ADJ_REASON_BIND_SERVICE = OOM_ADJ_REASON_METHOD + "_bindService";
 static final String OOM_ADJ_REASON_UNBIND_SERVICE = OOM_ADJ_REASON_METHOD + "_unbindService";
 static final String OOM_ADJ_REASON_START_SERVICE = OOM_ADJ_REASON_METHOD + "_startService";
 static final String OOM_ADJ_REASON_GET_PROVIDER = OOM_ADJ_REASON_METHOD + "_getProvider";
 static final String OOM_ADJ_REASON_REMOVE_PROVIDER = OOM_ADJ_REASON_METHOD + "_removeProvider";
 static final String OOM_ADJ_REASON_UI_VISIBILITY = OOM_ADJ_REASON_METHOD + "_uiVisibility";
 static final String OOM_ADJ_REASON_ALLOWLIST = OOM_ADJ_REASON_METHOD + "_allowlistChange";
 static final String OOM_ADJ_REASON_PROCESS_BEGIN = OOM_ADJ_REASON_METHOD + "_processBegin";
 static final String OOM_ADJ_REASON_PROCESS_END = OOM_ADJ_REASON_METHOD + "_processEnd"; 

通过更新原因可以看到,进程的状态变化,或者组件的状态变化会触发重新计算adj。

举例, 当一个APP处理广播时,就会触发重新计算这个APP的adj,此时的更新原因是OOM_ADJ_REASON_START_RECEIVER:

 private final void processCurBroadcastLocked(BroadcastRecord r,
              ProcessRecord app) throws RemoteException {
          ......
          r.receiver = thread.asBinder();
          r.curApp = app;
          final ProcessReceiverRecord prr = app.mReceivers;
          prr.addCurReceiver(r);
          app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
          mService.updateLruProcessLocked(app, false, null);
          // Make sure the oom adj score is updated before delivering the broadcast.
          // Force an update, even if there are other pending requests, overall it still saves time,
          // because time(updateOomAdj(N apps)) <= N * time(updateOomAdj(1 app)).
          mService.enqueueOomAdjTargetLocked(app);
          mService.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
          ......
      } 

OomAdjuster在computeOomAdjLSP中会将该app的adj提升至FOREGROUND_APP_ADJ:

 private boolean computeOomAdjLSP(ProcessRecord app, int cachedAdj,
              ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
              boolean computeClients) {
              ......
          } else if (state.getCachedIsReceivingBroadcast(mTmpBroadcastQueue)) {
              // An app that is currently receiving a broadcast also
              // counts as being in the foreground for OOM killer purposes.
              // It's placed in a sched group based on the nature of the
              // broadcast as reflected by which queue it's active in.
              adj = ProcessList.FOREGROUND_APP_ADJ;
              schedGroup = (mTmpBroadcastQueue.contains(mService.mFgBroadcastQueue))
                      ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
              state.setAdjType("broadcast");
              procState = ActivityManager.PROCESS_STATE_RECEIVER;
              if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                  reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making broadcast: " + app);
              }
          } 
          ...... 

2.3 Debounce time

当某个APP进程的adj达到CACHED_APP_MIN_ADJ时,CachedAppOptimizer就会调用freezeAppAsyncLSP,在debounce time之后,正式冰冻该进程, 这是为了防止进程在进入cached状态时还有任务没有完成从而间接影响用户体验。

Debounce time 在Android S 上默认是十分钟,这个值是可以在线修改的, 比如改为1秒:

adb shell device_config put activity_manager_native_boot freeze_debounce_timeout 1000 

修改后的值重启会失效,变回默认值。

与异步冰冻流程相反,解冻的过程是同步进行的,一个App进程一旦被解冻成功,它就立刻恢复正常运行。

2.4 freezeProcess

第一步,检查文件锁"/proc/locks"的状态。这是为了防止冰冻进程持有文件锁引起死锁。考虑到一些特殊场景下,进程在被冰冻的过程中拿住了文件锁,冰冻成功后还会再检查一次,发现持有锁就立刻解冻。

第二步,freeze binder。这一步禁掉该进程对同步binder请求的接收和处理,以及对异步binder请求的处理。该过程需要在100ms内成功,如果进程需要处理的请求过多导致无法完成,则再多给一轮debounce time。

第三步,setProcessFrozen,调用抽象层提供的API冰冻进程。

第四步,再次检查该进程有没有需要处理的binder请求,有则解冻进程,再多给一轮debounce time。这个检查是为一些特殊场景下,进程在被冰冻的过程中产生了binder请求。

2.5 setProcessFrozen

 void android_os_Process_setProcessFrozen( JNIEnv *env, jobject clazz, jint pid, jint uid, jboolean freeze)
  {
      bool success = true;
  
      if (freeze) {
          success = SetProcessProfiles(uid, pid, {"Frozen"});
      } else {
          success = SetProcessProfiles(uid, pid, {"Unfrozen"});
      }
  
      if (!success) {
          signalExceptionForGroupError(env, EINVAL, pid); 

调用cgroup抽象层的SetProcessProfiles, 传入参数“Frozen”。

3 cgroup 中间抽象层

cgroup中间抽象层libprocessgroup,主要提供两个功能,其一在启动阶段,根据cgroups.json 来装载具体的cgroup; 其二根据task_profiles.json来定义对cgroup具体的操作以及参数。 主要代码:

/system/core/libprocessgroup/ 

3.1 cgroups.json

示例文件:

{
  "Cgroups": [
    {
      "Controller": "cpu",
      "Path": "/dev/cpuctl",
      "Mode": "0755",
      "UID": "system",
      "GID": "system"
    },
    {
      "Controller": "memory",
      "Path": "/dev/memcg",
      "Mode": "0700",
      "Optional": true
    }
  ],
 "Cgroups2": {
   "Path": "/sys/fs/cgroup",
   "Mode": "0755",
   "UID": "system",
   "GID": "system",
   "Controllers": [
     {
       "Controller": "freezer",
       "Path": ".",
       "Mode": "0755",
       "UID": "system",
       "GID": "system"
     }
   ]
 }
} 

该文件分为两部分,“Cgroups” 描述cgroup v1 的控制子系统 和"Cgroups2" 描述cgroup v2的控制子系统。如果不了解cgroup 两个版本,可以参看以下网址:

www.kernel.org/doc/html/la… www.kernel.org/doc/html/la…

目前v1和v2是共存的, freezer所使用的是v2,对应根目录是/sys/fs/cgroup, UID和GID都是system。

启动阶段,Init在SetupCgroupAction中通过调用CgroupSetup,解析cgroups.json文件,完成对cgroup的装载。

需要注意的是,cgroups.json文件可能不止一个:

/system/core/libprocessgroup/profiles/cgroups.json              //默认文件,都有
/system/core/libprocessgroup/profiles/cgroups_<API level>.json  //API级别的文件,可能有
/vendor/xxx/cgroups.json                                        //vendor自定义的文件 

这三个文件加载的顺序是: 默认–> API级别 --> vendor,于是就存在一个覆盖的流程。只要后面一个文件中定义的"Controller"与前面的字符串相同,就会覆盖前者的定义。

形成的层级结构是这样的:

Android freezer 在/sys/fs/cgroup下建立了以uid/pid命名的二级子目录,对uid节点的控制会同步应用于其下面所有的pid节点。 uid在应用安装的时候确定, pid在应用使用的时候产生。如果manifest中使用了android:process,则在当前uid目录下建立一个新的pid开头的目录; 如果进程主动调用了fork产生子进程,则不会产生新的pid目录,而是放在父进程目录下,这就意味着父进程被冰冻的时候同目录的子进程也会被冰冻。

3.2 task_profiles.json

示例 task_profiles.json

 {
  "Attributes": [
     {
       "Name": "UClampLatencySensitive",
       "Controller": "cpu",
       "File": "cpu.uclamp.latency_sensitive"
     },
     {
       "Name": "FreezerState",
       "Controller": "freezer",
       "File": "cgroup.freeze"
     }
   ],
 
   "Profiles": [
     {
       "Name": "Frozen",
       "Actions": [
         {
           "Name": "SetAttribute",
           "Params":
           {
             "Name": "FreezerState",
             "Value": "1"
           }
         }
       ]
     },
     {
       "Name": "Unfrozen",
       "Actions": [
         {
           "Name": "SetAttribute",
           "Params":
           {
             "Name": "FreezerState",
             "Value": "0"
           }
         }
       ]
     },
    {
       "Name": "CpuPolicySpread",
       "Actions": [
         {
           "Name": "SetAttribute",
           "Params":
           {
             "Name": "UClampLatencySensitive",
             "Value": "1"
           }
         }
       ]
     }
   ],
 
   "AggregateProfiles": [
     {
       "Name": "SCHED_SP_BACKGROUND",
       "Profiles": [ "HighEnergySaving", "LowIoPriority", "TimerSlackHigh" ]
     }
   ]


**深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

![](https://img-blog.csdnimg.cn/direct/743b668910224b259a5ffe804fa6d0db.png)
![img](https://img-blog.csdnimg.cn/img_convert/b81c01078cc47958a8165730f909b09e.png)
![img](https://img-blog.csdnimg.cn/img_convert/8720b3d6a632247f2492e850d3daa982.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618636735)**

sdnimg.cn/direct/743b668910224b259a5ffe804fa6d0db.png)
[外链图片转存中...(img-QEF5yALi-1715607349654)]
[外链图片转存中...(img-sxCQ4f3f-1715607349655)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618636735)**

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值