Android 7系统无障碍服务(二)AccessibilityManagerService 启动与初始化
系列目录第一篇全景图与架构概览 | 第二篇AccessibilityManagerService 启动与初始化 | 第三篇无障碍服务的注册与绑定 | 第四篇AccessibilityEvent 的产生与投递 | 第五篇AccessibilityNodeInfo 的构建与查询 | 第六篇输入事件拦截与 TouchExplorer | 第七篇手势分发与 KeyEvent 处理 | 第八篇放大镜与辅助功能特性上一篇我们从宏观上梳理了无障碍服务的五层架构、核心类关系和三条主干数据流。本篇聚焦于整个无障碍模块的中枢——AccessibilityManagerService以下简称 AMS深入分析它从 SystemServer 启动到完成初始化的全过程。一、启动入口SystemServer.startOtherServices()AMS 的创建发生在 SystemServer 的startOtherServices()方法中与 ActivityManagerService、WindowManagerService 等核心服务一样属于系统启动的中后期阶段。源码路径frameworks/base/services/java/com/android/server/SystemServer.javaprivatevoidstartOtherServices(){// ... 大量其他服务的初始化 ...// 获取 WindowManagerService它在 AMS 之前初始化inputManagernewInputManagerService(context);wmWindowManagerService.main(context,inputManager,mFactoryTestMode!FactoryTest.FACTORY_TEST_LOW_LEVEL,!mFirstBoot,mOnlyCore,newPhoneWindowManager());// ... 其他服务 ...// 将已初始化的服务注册到 ServiceManagerServiceManager.addService(Context.WINDOW_SERVICE,wm);ServiceManager.addService(Context.INPUT_SERVICE,inputManager);// ...// 创建 AccessibilityManagerServiceaccessibilitynewAccessibilityManagerService(context);// 注册到 ServiceManager使客户端可以通过 Binder 获取ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,accessibility);}调用链路很简洁SystemServer.startOtherServices() → new AccessibilityManagerService(context) → ServiceManager.addService(Context.ACCESSIBILITY_SERVICE, accessibility)这里有两个值得注意的细节AMS 的创建时机在 WMS 之后但 WMS 实例并没有直接传递给 AMS 的构造函数。AMS 的构造函数仅接收Context后续需要 WMS 时通过LocalServices机制获取WindowManagerInternal——这是一种更晚绑定、更低耦合的设计。AMS 注册的服务名是Context.ACCESSIBILITY_SERVICE也就是字符串accessibility。客户端通过Context.getSystemService(Context.ACCESSIBILITY_SERVICE)拿到的就是 AMS 的 Binder 代理——实际上是IAccessibilityManager.Stub的代理对象。二、AMS 构造函数内部状态的初始化AMS 的构造函数完成了全部基础设施的搭建。源码路径frameworks/base/services/core/java/com/android/server/accessibility/AccessibilityManagerService.javapublicAccessibilityManagerService(Contextcontext){mContextcontext;// 创建 PackageManager 引用用于后续查询已安装的无障碍服务mPackageManagermContext.getPackageManager();// 创建 PowerManager 引用放大镜功能需要用 WakeLockmPowerManager(PowerManager)mContext.getSystemService(Context.POWER_SERVICE);// 初始化全局锁对象 —— 几乎所有对内部状态的修改都需持有此锁mLocknewObject();// 当前操作用户 ID初始化为当前活跃用户mCurrentUserIdActivityManager.getCurrentUser();// 创建主线程 HandlerAMS 中大量异步操作依赖它mMainHandlernewMainHandler(mContext.getMainLooper());// 向 WMS 注册无障碍焦点相关的 WindowManagerInternal// 通过 LocalServices 获取引用不直接持有 WMS// 初始化 UserState —— 每个用户独立的状态存储mUserStatesnewSparseArray();// 读取 Secure Settings 初始化当前用户的配置UserStateuserStatenewUserState(mCurrentUserId);mUserStates.put(mCurrentUserId,userState);readConfigurationForUserStateLocked(userState);// 注册 Settings.Secure 内容观察者registerSettingsContentObservers(mCurrentUserId);// 注册系统广播接收器registerBroadcastReceivers();}构造函数中的初始化可以归为以下几类2.1 系统服务引用变量类型用途mPackageManagerPackageManager查询已安装无障碍服务列表、解析 ServiceInfomPowerManagerPowerManager放大镜功能需要防止屏幕超时WakeLockmLockObject全局同步锁保护内部状态的一致性2.2 匿名 BindermServicemService是 AMS 内部最核心的服务端 Binder一个匿名IAccessibilityManager.Stub实现。所有来自AccessibilityManager客户端和AccessibilityService的跨进程调用都通过这个 Binder 进入 AMS。// 源码路径frameworks/base/services/core/java/com/android/server/accessibility/AccessibilityManagerService.javaprivatefinalIAccessibilityManager.StubmServicenewIAccessibilityManager.Stub(){OverridepublicvoidsendAccessibilityEvent(AccessibilityEventevent,intuserId){// 第四篇重点事件的跨进程入口}OverridepublicbooleansendFingerprintGesture(intkeyCode){// 指纹手势的无障碍处理}OverridepublicListAccessibilityServiceInfogetInstalledAccessibilityServiceList(intuserId){// 查询已安装的无障碍服务列表}OverridepublicListAccessibilityServiceInfogetEnabledAccessibilityServices(intfeedbackType){// 查询已启用的无障碍服务列表}Overridepublicvoidinterrupt(intuserId){// 中断所有无障碍服务的当前操作}OverridepublicintaddClient(IAccessibilityManagerClientclient,intuserId){// 客户端注册回调用于状态变化通知}OverridepublicvoidregisterUiTestAutomationService(IBinderowner,IAccessibilityServiceClientclient,AccessibilityServiceInfoinfo,intflags){// UiAutomation 测试框架专用的注册入口}// ... 更多接口方法涵盖事件投递、服务管理、状态查询等};这个匿名 Binder 通过onBind()暴露给 ServiceManagerOverridepublicIBinderonBind(Intentintent){returnmService;}当ServiceManager.addService(Context.ACCESSIBILITY_SERVICE, accessibility)执行时系统会将mService注册到 ServiceManager使所有进程都能通过 Binder 查询到它。mService中的每个方法几乎都遵循同一个调用模式Binder 线程 → 获取 mLock → 切 mMainHandler → 执行业务逻辑这种Binder 线程加锁 Handler 切主线程的双重保护确保了多线程环境下内部状态的一致性。2.3 mMainHandler主线程消息处理AMS 内部定义了一个MainHandler是Handler的子类承载了大量延时任务和异步回调的分发// 源码路径frameworks/base/services/core/java/com/android/server/accessibility/AccessibilityManagerService.javaprivatefinalclassMainHandlerextendsHandler{publicstaticfinalintMSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER1;publicstaticfinalintMSG_SEND_KEY_EVENT_TO_INPUT_FILTER2;publicstaticfinalintMSG_SEND_STATE_TO_CLIENTS3;publicstaticfinalintMSG_CLEAR_ACCESSIBILITY_CACHE4;publicstaticfinalintMSG_ANNOUNCE_NEW_USER_IF_NEEDED5;publicstaticfinalintMSG_CLEAR_ACCESSIBILITY_FOCUS6;publicMainHandler(Looperlooper){super(looper);}OverridepublicvoidhandleMessage(Messagemsg){switch(msg.what){caseMSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER:// 将事件发送到 InputFilter 链供 TouchExplorer 等处理notifyAccessibilityServicesDelayedLocked(...);break;caseMSG_SEND_KEY_EVENT_TO_INPUT_FILTER:// 发送按键事件到 InputFilter 链break;caseMSG_SEND_STATE_TO_CLIENTS:// 通知所有已注册客户端无障碍状态变化break;caseMSG_CLEAR_ACCESSIBILITY_CACHE:// 通知所有 AccessibilityService 清除内部缓存break;caseMSG_ANNOUNCE_NEW_USER_IF_NEEDED:// 多用户切换时的语音提示break;caseMSG_CLEAR_ACCESSIBILITY_FOCUS:// 清除无障碍焦点break;}}}这些消息类型覆盖了事件投递第四篇、状态广播、缓存清理第五篇等后续各篇涉及的核心流程。理解 MainHandler 的消息模型是理解整个 AMS 异步机制的基石。三、UserState多用户状态隔离Android 7 支持多用户Multi-User每个用户拥有独立的无障碍服务配置和运行时状态。AMS 通过UserState内部类实现用户级隔离以SparseArrayUserState存储所有用户状态键为用户 ID。源码路径frameworks/base/services/core/java/com/android/server/accessibility/AccessibilityManagerService.javaprivateclassUserState{// 用户 IDpublicfinalintmUserId;// 持久化配置项来自 Settings.Secure// 已启用的无障碍服务列表ComponentName 字符串冒号分隔publicStringmEnabledServicesStr;// 触摸探索模式是否允许publicbooleanmTouchExplorationGranted;// 放大镜是否开启publicbooleanmMagnificationEnabled;// 无障碍快捷方式是否开启publicbooleanmAccessibilityShortcutEnabled;// 无障碍快捷方式对应的目标服务 ComponentNamepublicStringmAccessibilityShortcutTarget;// 高对比度文字是否开启publicbooleanmHighTextContrastEnabled;// 字体缩放比例publicfloatmFontScale;// 运行时状态 // 已绑定并正在运行的无障碍服务列表publicfinalListServicemBoundServicesnewArrayList();// 正在绑定中的服务ComponentName 集合publicfinalSetComponentNamemBindingServicesnewHashSet();// 已安装的无障碍服务信息缓存publicListAccessibilityServiceInfomInstalledServices;// 无障碍是否全局开启publicbooleanmEnabled;// 当前有无障碍焦点的窗口 IDpublicintmAccessibilityFocusWindowId-1;// 当前有无障碍焦点的节点 IDpubliclongmAccessibilityFocusNodeIdAccessibilityNodeInfo.UNDEFINED_ITEM_ID;// ContentObserver 引用切换用户时用于注销publicContentObservermContentObserver;// 广播接收器列表publicfinalListBroadcastReceivermReceiversnewArrayList();}多用户切换时AMS 的switchUser()方法会在当前 UserState 上调用unbindAllServicesLocked()停止所有服务切换到目标 UserState在目标 UserState 上调用bindServicesLocked()重新绑定该用户启用的服务mUserStates的SparseArray结构确保了不同用户间的状态完全隔离。四、Settings.Secure 配置项读取与初始化无障碍服务的大部分开关和配置都通过Settings.Secure持久化存储。AMS 在初始化 UserState 时需要一次性读取所有相关配置并缓存到内存。4.1 关键 Secure 配置项一览配置项 Key类型含义ACCESSIBILITY_ENABLEDint (0/1)无障碍功能全局开关ENABLED_ACCESSIBILITY_SERVICESString已启用的无障碍服务列表格式pkg/ServiceCls:pkg2/ServiceClsTOUCH_EXPLORATION_ENABLEDint (0/1)触摸探索模式开关ACCESSIBILITY_SHORTCUT_ENABLEDint (0/1)无障碍快捷方式开关ACCESSIBILITY_SHORTCUT_TARGET_SERVICEString快捷方式目标服务 ComponentNameACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLEDint (0/1)放大镜开关ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLEDint (0/1)高对比度文字开关FONT_SCALEfloat字体缩放比例ACCESSIBILITY_SCRIPT_INJECTIONint (0/1)允许服务注入网页脚本4.2 readConfigurationForUserStateLocked()这个方法在初始化时被调用将所有 Secure 配置一次性读取并缓存到 UserStateprivatevoidreadConfigurationForUserStateLocked(UserStateuserState){// 全局开关userState.mEnabled(Settings.Secure.getIntForUser(mContext.getContentResolver(),Settings.Secure.ACCESSIBILITY_ENABLED,0,userState.mUserId)1);// 已启用的服务列表字符串userState.mEnabledServicesStrSettings.Secure.getStringForUser(mContext.getContentResolver(),Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,userState.mUserId);// 触摸探索userState.mTouchExplorationGranted(Settings.Secure.getIntForUser(mContext.getContentResolver(),Settings.Secure.TOUCH_EXPLORATION_ENABLED,0,userState.mUserId)1);// 放大镜userState.mMagnificationEnabled(Settings.Secure.getIntForUser(mContext.getContentResolver(),Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,0,userState.mUserId)1);// 高对比度文字userState.mHighTextContrastEnabled(Settings.Secure.getIntForUser(mContext.getContentResolver(),Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,0,userState.mUserId)1);// ... 其他配置项 ...}后续所有状态判断都直接使用内存缓存而不是每次都查询 ContentProvider这是一个典型的性能优化策略。五、ContentObserver配置变化的实时监听仅仅读取初始值是不够的——用户在设置 → 无障碍中修改任何开关AMS 都必须立即响应。这是通过ContentObserver实现的。源码路径frameworks/base/services/core/java/com/android/server/accessibility/AccessibilityManagerService.javaprivatevoidregisterSettingsContentObservers(intuserId){UserStateuserStategetUserStateLocked(userId);ContentObserverobservernewContentObserver(mMainHandler){OverridepublicvoidonChange(booleanselfChange,Uriuri){synchronized(mLock){UserStateuserStategetCurrentUserStateLocked();// 无障碍全局开关变化 → 更新状态并重新绑定/解绑服务if(userState.mEnabled!isAccessibilityEnabled()){userState.mEnabledisAccessibilityEnabled();if(userState.mEnabled){bindServicesLocked(userState);// 关→开绑定服务}else{unbindAllServicesLocked(userState);// 开→关解绑全部}notifyClientsOfStateChangeLocked(userState);}// 已启用服务列表变化 → 重新绑定StringnewServicesStrSettings.Secure.getStringForUser(mContext.getContentResolver(),Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,userId);if(!newServicesStr.equals(userState.mEnabledServicesStr)){userState.mEnabledServicesStrnewServicesStr;unbindAllServicesLocked(userState);bindServicesLocked(userState);}// 触摸探索开关变化 → 重新配置 InputFilter// 放大镜开关变化 → 重新配置 MagnificationController// ...}}};ContentResolverresolvermContext.getContentResolver();// 为每个关键 URI 注册监听resolver.registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_ENABLED),false,observer,userId);resolver.registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES),false,observer,userId);resolver.registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.TOUCH_EXPLORATION_ENABLED),false,observer,userId);// ... 更多 URI 注册userState.mContentObserverobserver;}这里有三个关键设计细节**回调在 m

相关新闻

计算机毕业设计之基于Python用户购物行为分析

计算机毕业设计之基于Python用户购物行为分析

由于移动应用技术的持续性的快速发展,现实生活中人们大多数都是通过移动手机、电脑等智能设备来完成生活中的事务。因此,许多的人工传统行业也开始与互联网结合,不再一味的依靠人工劳动,努力打造半自动数字化甚至是全自动数字化模…

2026/8/13 23:37:00 阅读更多 →
千问    LeetCode 3887. 增量偶权环查询 C++实现

千问 LeetCode 3887. 增量偶权环查询 C++实现

这道题的核心是带权并查集,将"环边权和为偶数"转化为"环上边权异或和为 0",通过维护每个节点到根的异或距离来判断新边是否会形成奇权环。核心思路1. 问题转化:边权为 0 或 1,环的边权和为偶数 ⟺ 环上所有边…

2026/8/13 23:36:59 阅读更多 →
SSH终端的剪切粘贴和移动的区别

SSH终端的剪切粘贴和移动的区别

背景 由于很多工具本身就不支持SSH协议远程的移动功能,所以很多网友对于SSH的移动没有感触,但是移动的性能远远高于剪切和复制,而且对于文件的Linux权限属性保存的最为完整,所以很多场景下是极为有用的。今天就使用DESK倚天剑比较…

2026/8/13 23:36:59 阅读更多 →

最新新闻

网页爬虫的法律边界与合规技术实践

网页爬虫的法律边界与合规技术实践

1. 网页爬取的法律边界与行业现状 第一次接触网页爬取技术时,我和大多数开发者一样,最关心的不是技术实现,而是"这玩意儿到底能不能用"。2019年某电商平台起诉爬虫开发者的案件,让整个技术圈都开始重新审视这个灰色地带…

2026/8/15 2:05:05 阅读更多 →
Oracle分页查询性能优化:从ROWNUM原理到千万级数据实战

Oracle分页查询性能优化:从ROWNUM原理到千万级数据实战

1. 从一次深夜告警说起:为什么分页查询不是小事那天晚上十一点,我正打算关电脑,突然收到监控系统的告警,提示某个核心业务接口的响应时间飙升到了5秒以上。登录服务器一看,CPU和内存都还正常,但数据库的活跃…

2026/8/15 2:05:05 阅读更多 →
如何用 BoneAnimCopy 在 Blender 中一步到位复制骨骼动画:新手完整指南

如何用 BoneAnimCopy 在 Blender 中一步到位复制骨骼动画:新手完整指南

如何用 BoneAnimCopy 在 Blender 中一步到位复制骨骼动画:新手完整指南 【免费下载链接】blender_BoneAnimCopy 用于在blender中桥接骨骼动画的插件 项目地址: https://gitcode.com/gh_mirrors/bl/blender_BoneAnimCopy 做独立游戏或短片动画时,你…

2026/8/15 2:05:05 阅读更多 →
抖音批量下载工具douyin-downloader完整上手指南:去水印、批量抓取、直播录制一站搞定

抖音批量下载工具douyin-downloader完整上手指南:去水印、批量抓取、直播录制一站搞定

抖音批量下载工具douyin-downloader完整上手指南:去水印、批量抓取、直播录制一站搞定 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplicati…

2026/8/15 2:05:05 阅读更多 →
基于OpenClaw框架构建AI智能体:从自动化工作流到个人数字管家

基于OpenClaw框架构建AI智能体:从自动化工作流到个人数字管家

1. 项目概述:从“钢铁侠”的幻想走进现实还记得《钢铁侠》里那个无所不能的贾维斯(Jarvis)吗?它能处理邮件、管理日程、控制智能家居,甚至能和托尼斯塔克斗嘴。过去,这只是科幻电影里的酷炫设定&#xff0c…

2026/8/15 2:05:05 阅读更多 →
1.6 窗口布局

1.6 窗口布局

1. 布局的样式为什么要布局:1. 布局之后窗口的排列是有序的 2. 布局之后窗口的大小发生变化, 控件的大小也会对应变化 3. 如果不对控件布局, 窗口显示出来之后有些控件的看不到的布局可以嵌套使用Qt窗口布局是指将多个子窗口按照某种排列方式将其全部展示到对应的父窗口中的一种…

2026/8/15 2:04:05 阅读更多 →

日新闻

内景 空间站内部 中国空间站 太空 内仓

内景 空间站内部 中国空间站 太空 内仓

本项目为前几天收费帮学妹做的一个项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。 一、项目描述 空间站内部 中国空间站 太空 内仓 地址:本地PC端运行(或Web…

2026/8/15 0:00:30 阅读更多 →
重新定义数据接口:3个突破性场景让通达信数据读取更智能

重新定义数据接口:3个突破性场景让通达信数据读取更智能

重新定义数据接口:3个突破性场景让通达信数据读取更智能 【免费下载链接】mootdx 通达信数据读取的一个简便使用封装 项目地址: https://gitcode.com/GitHub_Trending/mo/mootdx 当我们面对海量金融数据时,传统的数据获取方式往往让我们陷入困境—…

2026/8/15 0:00:30 阅读更多 →
一文读懂快消WMS怎么选?2026年国内外10大主流WMS品牌盘点

一文读懂快消WMS怎么选?2026年国内外10大主流WMS品牌盘点

快消品(FMCG)是流通速度较快、竞争较为激烈的行业之一。一瓶饮料从出厂到消费者手中,往往只有几十天甚至几天的周转窗口。这决定了快消行业的仓储管理系统(WMS)与制造业、电商行业存在明显区别:它不仅需要管…

2026/8/15 0:02:30 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/13 2:38:34 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/13 10:41:52 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/13 10:41:51 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/14 13:40:53 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/14 14:06:45 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/13 10:41:49 阅读更多 →