Android SystemServer 系列專題【AttentionManagerService】

AttentionManagerService是framework中用來實現屏幕感知的一個系統級服務,他繼承于systemserver。我們可以通過dumpsys?attention來獲取他的一些信息。

如下針對屏幕感知的功能的引入來針對這個服務進行一個介紹。

1、屏幕感知Settings UI實現

屏幕感知的功能在A14上面默認都支持,其入口在設置->顯示->屏幕超時->屏幕感知。

根據其描述他會檢測到如果你在定制屏幕看,就會阻止屏幕超時息屏。

Settings UI控制代碼:AdaptiveSleepPreferenceController.java

如上的開關看起來是在isChecked這里實現,主要判斷了一些條件來進行顯示,這個開關的key是:adaptive_sleep,為1表示此功能開啟

2、屏幕感知FW Client實現

通過搜索ADAPTIVE_SLEEP發現fw只有如下一個地方在使用:

//frameworks/base/services/core/java/com/android/server/power/AttentionDetector.java
public class AttentionDetector {private static final String TAG = "AttentionDetector";private static final boolean DEBUG = false;private Context mContext;private boolean mIsSettingEnabled;@VisibleForTestingAttentionCallbackInternalImpl mCallback;public AttentionDetector(Runnable onUserAttention, Object lock) {mOnUserAttention = onUserAttention;mLock = lock;mRequested = new AtomicBoolean(false);mRequestId = 0;// Device starts with an awake state upon boot.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;}@VisibleForTestingvoid updateEnabledFromSettings(Context context) {//判斷Settings的屏幕感知功能是否使能mIsSettingEnabled = Settings.Secure.getIntForUser(context.getContentResolver(),Settings.Secure.ADAPTIVE_SLEEP, 0, UserHandle.USER_CURRENT) == 1;}//屏幕感知核心功能,PowerManagerService#updateUserActivitySummaryLocked會調用到這里//即PowerManagerService在進行屏幕喚醒或者息屏以及應用鎖持有計算的時候進行調用,因此這里會影響屏幕超時息屏的邏輯 To be called in {@link PowerManagerService#updateUserActivitySummaryLocked} public long updateUserActivity(long nextScreenDimming, long dimDurationMillis) {// 1. 前置條件檢查:滿足任一條件則直接返回原定的變暗時間if (nextScreenDimming == mLastActedOnNextScreenDimming  // 已處理過相同變暗時間|| !mIsSettingEnabled           // 功能未啟用|| !isAttentionServiceSupported() // 設備不支持注意力檢測服務|| mWindowManager.isKeyguardShowingAndNotOccluded()) { // 當前處于鎖屏狀態return nextScreenDimming;}// 2. 計算關鍵時間節點final long now = SystemClock.uptimeMillis(); // 當前系統啟動時間(毫秒)final long whenToCheck = nextScreenDimming - mPreDimCheckDurationMillis; // 檢測觸發時間(變暗前提前量)final long whenToStopExtending = mLastUserActivityTime + mMaximumExtensionMillis; // 最長可延時時限// 3. 時間窗口判斷邏輯if (now < whenToCheck) { // 未到檢測時間:返回下次應檢測的時間點(DEBUG模式輸出日志)if (DEBUG) Slog.d(TAG, "Do not check for attention yet, wait " + (whenToCheck - now));return whenToCheck;} else if (whenToStopExtending < whenToCheck) {// 超過最大延時時長:放棄檢測直接允許變暗(安全策略)if (DEBUG) Slog.d(TAG, "Let device sleep to avoid false results...");return nextScreenDimming;} else if (mRequested.get()) {// 已有未完成的檢測請求:等待當前請求完成if (DEBUG) Slog.d(TAG, "Pending attention callback with ID=" + mCallback.mId + ", wait.");return whenToCheck;}// 4. 發起屏幕感知檢測請求mRequested.set(true); // 標記請求狀態mRequestId++;         // 生成唯一請求IDmLastActedOnNextScreenDimming = nextScreenDimming; // 記錄當前處理的變暗時間mCallback = new AttentionCallbackInternalImpl(mRequestId); // 創建回調實例// 5. 計算實際檢測超時時間(取配置值與剩余變暗時間的較小值)mEffectivePostDimTimeoutMillis = Math.min(mRequestedPostDimTimeoutMillis, dimDurationMillis);// 6. 調用系統服務檢測用戶注意力Slog.v(TAG, "Checking user attention, ID: " + mRequestId);final boolean sent = mAttentionManager.checkAttention(mPreDimCheckDurationMillis + mEffectivePostDimTimeoutMillis,mCallback);// 7. 請求失敗處理if (!sent) {mRequested.set(false); // 重置請求狀態}return whenToCheck; // 返回建議的下次檢測時間}
}

綜上最核心的方法如下:

1)Attention注意力檢查請求

每次從pms那邊過來就會請求一次是否有人眼盯著屏幕看,每次請求都有唯一標準ID,可以參考如下日志:

130|OrderPAD_3:/ $ logcat | grep -E "AttentionManagerService|AttentionDetector"
09-04 11:22:26.250  2307  2372 V AttentionDetector: Checking user attention, ID: 40
09-04 11:22:28.258  2307  3160 V AttentionDetector: onSuccess: 0, ID: 40
09-04 11:23:08.249  2307  2372 V AttentionDetector: Checking user attention, ID: 41
09-04 11:23:10.258  2307  2409 V AttentionDetector: onSuccess: 0, ID: 41
09-04 11:23:42.238  2307  2372 V AttentionDetector: Checking user attention, ID: 42
09-04 11:23:44.246  2307  4514 V AttentionDetector: onSuccess: 0, ID: 42
09-04 11:27:38.810  2307  2372 V AttentionDetector: Checking user attention, ID: 43
09-04 11:27:40.831  2307  3177 V AttentionDetector: onSuccess: 0, ID: 43

2)Attention檢查結果返回

//frameworks/base/services/core/java/com/android/server/power/AttentionDetector.java 
@Override
public void onSuccess(int result, long timestamp) {// 1. 日志記錄檢測結果(VERBOSE級別日志,包含結果碼和請求ID)Slog.v(TAG, "onSuccess: " + result + ", ID: " + mId);// 2. 防循環處理:驗證請求ID有效性并原子性重置請求狀態// - mId == mRequestId:確保回調匹配當前最新請求(避免舊請求干擾)// - mRequested.getAndSet(false):原子操作標記請求已完成if (mId == mRequestId && mRequested.getAndSet(false)) {// 3. 同步鎖保護關鍵代碼塊(防止多線程競爭條件)synchronized (mLock) {// 4. 設備狀態檢查:若非喚醒狀態則直接返回(如已進入休眠)if (mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE) {if (DEBUG) Slog.d(TAG, "Device slept before receiving callback.");return;}// 5. 根據檢測結果執行分支邏輯if (result == AttentionService.ATTENTION_SUCCESS_PRESENT) {// 5.1 檢測到用戶注意力:觸發延屏操作(如執行mOnUserAttention回調)mOnUserAttention.run();} else {// 5.2 未檢測到注意力:重置連續延屏計數(統計上報邏輯)resetConsecutiveExtensionCount();}}}
}

3、屏幕感知FW Service實現

在此回到attention的檢查請求,是直接調用了mAttentionManager.checkAttention,根據經驗,其實就是調用到了AttentionManagerService.java如下代碼:

//frameworks/base/services/core/java/com/android/server/attention/AttentionManagerService.java 
boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) {Objects.requireNonNull(callbackInternal);//流程1:服務可用性檢查(三級防御式編程)if (!mIsServiceEnabled) { // 設備硬件不支持該服務Slog.w(LOG_TAG, "Trying to call checkAttention() on an unsupported device.");return false;}if (!isServiceAvailable()) { // 服務進程未就緒Slog.w(LOG_TAG, "Service is not available at this moment.");return false;}// 攝像頭被系統級禁用if (mPrivacyManager.isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA)) {Slog.w(LOG_TAG, "Camera is locked by a toggle.");return false;}// 電源狀態檢查:屏幕關閉或省電模式下禁止檢測if (!mPowerManager.isInteractive() || mPowerManager.isPowerSaveMode()) {return false;}//流程2: 服務綁定與緩存管理(線程安全),這里其實要去發送intent移交其他組件來實現Attention檢查synchronized (mLock) {freeIfInactiveLocked();bindLocked();}// 阻塞等待intent那邊組件完全啟動final long now = SystemClock.uptimeMillis();awaitServiceBinding(Math.min(SERVICE_BINDING_WAIT_MILLIS, timeout));//流程3:核心業務邏synchronized (mLock) {final AttentionCheckCache cache = mAttentionCheckCacheBuffer == null ? null : mAttentionCheckCacheBuffer.getLast();if (cache != null && now < cache.mLastComputed + mStaleAfterMillis) {callbackInternal.onSuccess(cache.mResult, cache.mTimestamp); return true;}//請求限流:同一時間只允許一個未完成的請求if (mCurrentAttentionCheck != null) {if (!mCurrentAttentionCheck.mIsDispatched || ! mCurrentAttentionCheck.mIsFulfilled)  return false;}//創建新檢測請求:其實把Attention請求的實現轉移給到了前面流程2啟動的intent的組件來實現mCurrentAttentionCheck = new AttentionCheck(callbackInternal, this);if (mService != null) {try {cancelAfterTimeoutLocked(timeout); mService.checkAttention(mCurrentAttentionCheck.mIAttentionCallback); mCurrentAttentionCheck.mIsDispatched = true;} catch (RemoteException e) {Slog.e(LOG_TAG, "Cannot call into the AttentionService");return false;}}return true;}
}

AttentionManagerService實現的checkAttention方法來看,貌似他也沒有來實現具體邏輯,而是作為一個中間人也去調用了一個mService.checkAttention里面去進行調用,它已經是一個系統級服務了,為什么還存在一個mService呢?先劇透一下,他其實依賴其他com.google.android.as來完成attention注意力感知的邏輯實現。

1)綁定google as服務

在checkAttention方法中通過bindLocked去綁定google as服務,其實就是普通的一個服務綁定,這里傳遞了mConnection來接收Binder對端,他的定義如下:

google as服務綁定成功,拿到service并賦值給mService,后續的checkAttention通過google as服務區實現

2)調用google as服務

這里發現了兩處去調用google as服務的,但是基本實現邏輯基本一致:

  • 服務綁定成功的時候觸發一次handlePendingCallbackLocked

  • PMS間歇式調用checkAttention/如果mService不為null直接請求

如上兩種場景其實就是綁定服務后的第一次觸發和后面的輪詢觸發。原理都一致。

3)為什么是google as服務?

從第一小節的bindLocked方法可以看到她并不是隱式的去啟動attention服務,而是直接指定了包名:

            final Intent serviceIntent = new Intent(AttentionService.SERVICE_INTERFACE).setComponent(mComponentName);

這里的mComponentName到底是誰?通過dump出來的答案就是

AttentionServicePackageName=com.google.android.as
Resolved component:Component=com.google.android.asClass=com.google.android.apps.miphone.aiai.attention.service.AiAiAttentionService

我們接著來研究一下為什么是google as:

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/96174.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/96174.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/96174.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

nginx 反向代理使用變量的坑

nginx采用反向代理的時候使用變量的坑 正常情況&#xff1a; location ~ ^/prod-api(?<rest>/.*)?$ {# 假設 $mes_backend 形如: http://127.0.0.1:16889proxy_pass $mes_backend$rest$is_args$args;proxy_http_version 1.1;proxy_set_header Host $host;…

Origin繪制徑向條形圖|科研論文圖表教程

數據排列格式截圖&#xff0c;請查看每張圖↘右下角水印 目錄 數據排列格式截圖&#xff0c;請查看每張圖↘右下角水印 本 期 導 讀 No.1 理解圖形 1 定義 2 特點 3 適用場景 No.2 畫圖教程 1 導入數據&#xff0c;繪制圖形 2 設置繪圖細節 本 期 導 讀 徑…

MySQL InnoDB 的 MVCC 機制

前言 多版本并發控制&#xff08;MVCC&#xff09;是 MySQL InnoDB 存儲引擎實現高性能事務的核心機制。它通過創建數據快照&#xff0c;使得讀寫操作可以無鎖并發&#xff0c;極大地提升了數據庫的并發性能。本文將深入探討 MVCC 的工作原理、實現細節以及它與事務隔離級別的緊…

景區負氧離子氣象站:引領綠色旅游,暢吸清新每一刻

在綠色旅游成為消費主流的今天&#xff0c;游客對 “清新空氣” 的需求不再是模糊的期待&#xff0c;而是可感知、可選擇的具體體驗。景區負氧離子氣象站的出現&#xff0c;正以科技之力重塑綠色旅游格局&#xff0c;讓 “暢吸清新每一刻” 從口號變為觸手可及的現實&#xff0…

Pytorch筆記一之 cpu模型保存、加載與推理

Pytorch筆記一之 cpu模型保存、加載與推理 1.保存模型 首先&#xff0c;在加載模型之前&#xff0c;我們需要了解如何保存模型。PyTorch 提供了兩種保存模型的方法&#xff1a;保存整個模型和僅保存模型的狀態字典&#xff08;state dict&#xff09;。推薦使用第二種方式&…

當AI在代碼車間組裝模塊:初級開發者的創意反成「核心算法」

前言&#xff1a;哈嘍&#xff0c;大家好&#xff0c;今天給大家分享一篇文章&#xff01;并提供具體代碼幫助大家深入理解&#xff0c;徹底掌握&#xff01;創作不易&#xff0c;如果能幫助到大家或者給大家一些靈感和啟發&#xff0c;歡迎收藏關注哦 &#x1f495; 目錄當AI在…

技術視界 | 跨域機器人通信與智能系統:打破壁壘的開源探索

8 月 16 日&#xff0c;在 OpenLoong 社區舉辦的第九期線下分享會上&#xff0c;國家地方共建人形機器人創新中心的軟件開發負責人 Amadeus 博士帶來了一場主題為“跨域機器人通信與智能系統&#xff1a;打破行業壁壘的創新方案”的演講。深入探討了當前機器人領域的一個關鍵痛…

Android入門到實戰(八):從發現頁到詳情頁——跳轉、傳值與RecyclerView多類型布局

一. 引言在上一篇文章里&#xff0c;我們從零開始實現了 App 的 發現頁面&#xff0c;通過網絡請求獲取數據&#xff0c;并使用 RecyclerView 展示了劇集列表。但光有發現頁還不夠&#xff0c;用戶在點擊一部劇時&#xff0c;自然希望進入到一個更詳細的頁面&#xff0c;去查看…

【工具】41K star!網頁一鍵變桌面應用

項目中遇到了一個需要將現有的 web 頁面打包成一個 桌面應用 的需求。 最一開始想到的是 Electron&#xff0c;但是它還需要一些開發工作并且打包后的應用體積比較大&#xff0c;調研后發現了開源工具 Pake。 它能讓你用最輕量的方式&#xff0c;把任何網頁一鍵打包成跨平臺桌…

浪潮CD1000-移動云電腦-RK3528芯片-2+32G-安卓9-2種開啟ADB ROOT刷機教程方法

浪潮CD1000-移動云電腦-RK3528芯片-232G-安卓9-2種開啟ADB ROOT刷機教程方法 往期文章&#xff1a; 浪潮CD1000-移動云電腦-RK3528芯片-232G-安卓9-開啟ADB ROOT破解教程 地址1&#xff1a;浪潮CD1000-移動云電腦-RK3528芯片-232G-開啟ADB ROOT破解教程-CSDN博客 中國移動浪潮…

Day23_【機器學習—聚類算法—K-Means聚類 及評估指標SSE、SC、CH】

一、聚類算法概念屬于無監督學習算法&#xff0c;即有特征無標簽&#xff0c;根據樣本之間的相似性&#xff0c;將樣本劃分到不同的類別中。所謂相似性可以理解為歐氏距離、曼哈頓距離、切比雪夫距離... 。分類按顆粒度分為&#xff1a;粗聚類、細聚類。按實現方法分為&#xf…

android seekbar顯示刻度

SeekBar簡介 SeekBar是Android中的一個可交互UI組件&#xff0c;允許用戶通過拖動滑塊在特定范圍內選擇數值。繼承自ProgressBar&#xff0c;但增加了用戶手動調節功能&#xff0c;常用于音量控制、亮度調節等場景。 核心屬性 android:maxHeight // 背景高度 android:progres…

【高并發內存池】五、頁緩存的設計

文章目錄Ⅰ. page cache頁緩存的結構設計Ⅱ. 完善central cache中的 get_span() 函數Ⅲ. 實現頁緩存獲取span對象的接口Ⅰ. page cache頁緩存的結構設計 ? 首先頁緩存還是一個哈希桶的結構&#xff0c;但是和前兩者不同的是&#xff0c;頁緩存的哈希桶中存放的是一個或者多個…

Elasticsearch(text和keyword)區別分析

text:全文檢索類型,經過分詞處理,支持模糊匹配? keyword:精確匹配類型,適用于聚合、排序和過濾? text 1. 核心屬性 ?analyzer屬性?: 指定用于索引和搜索的分詞器 默認使用標準分析器(Standard Analyzer) 示例:"analyzer": "ik_max_word"(中文…

通過tailscale實現一臺電腦上vscode通過ssh連接另一臺電腦上的VMware Linux 虛擬機

當需要通過一臺windows電腦上的vscode來ssh連接另一臺電腦上的linux虛擬機進行遠程操作&#xff0c;可以通過tailscale來實現。 Linux虛擬機上安裝tailscale 由于掛代理下載仍然很慢&#xff0c;而清華鏡像源又沒有tailscale的軟件包&#xff0c;所以可以通過下載 DEB 包安裝…

[Upscayl圖像增強] docs | 前端 | Electron工具(web->app)

鏈接&#xff1a;https://upscayl.org/docs&#xff1a;Upscayl Upscayl是一款桌面應用程序&#xff0c;允許用戶使用人工智能放大和增強圖像。 提供了一個用戶友好的圖形界面&#xff08;渲染器用戶界面&#xff09;&#xff0c;用戶可以選擇圖像或文件夾&#xff0c;從多種AI…

阿里云通義MoE全局均衡技術:突破專家負載失衡的革新之道

MoE模型的基本原理與核心價值 混合專家模型&#xff08;Mixture of Experts&#xff0c;MoE&#xff09;是當前AI大模型領域最重要的架構創新之一&#xff0c;其核心思想是通過多個“專家”網絡協同處理輸入數據&#xff0c;并由門控網絡動態選擇或組合各個專家的輸出&#xf…

macOS中設置環境變量的各文件及作用域

在 macOS 中&#xff0c;~/.zshrc 和 ~/.bash_profile 是 Shell 的配置文件&#xff0c;用于設置環境變量、命令別名、啟動命令等。它們在你每次打開終端時會被自動加載。文件對應 Shell作用~/.zshrcZsh&#xff08;macOS Catalina 及以后默認&#xff09;每次打開新的終端窗口…

【華為培訓筆記】OptiX OSN 9600 設備保護專題

OptiX OSN 9600 設備保護專題 1、光層保護 定義 方式 應用

Python開篇撬動未來的萬能鑰匙 從入門到架構的全鏈路指南

&#x1f49d;&#x1f49d;&#x1f49d;歡迎蒞臨我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 持續學習&#xff0c;不斷…