Android 的账户与同步框架提供两个紧耦合的子系统:AccountManager用于凭证存储与身份令牌管理;SyncManager用于调度和执行后台数据同步。二者共同构成所有与远端服务器同步数据的应用的底层支撑,涵盖邮件、联系人、企业 MDM 以及第三方云服务。
本章完整梳理整套架构:从面向应用的AccountManager与ContentResolver.requestSync()API,到 system_server 内部实现(AccountManagerService、SyncManager),再到底层数据库存储以及与JobScheduler的集成。
32.1 AccountManager 架构
32.1.1 三层设计
账户子系统遵循 AOSP 标准分层架构:
框架 API(Java)—android.accounts.AccountManager,面向应用的入口类,提供账户发现、凭证管理、身份令牌获取能力。
系统服务—AccountManagerService运行于 system_server 进程,实现IAccountManagerAIDL 接口。管理账户数据库、认证器绑定、令牌缓存。
认证器插件— 第三方或设备厂商实现AbstractAccountAuthenticator,负责对应账户类型实际的凭证校验与令牌生成。
源码路径(关键文件):
AccountManager ................. frameworks/base/core/java/android/accounts/AccountManager.java Account ........................ frameworks/base/core/java/android/accounts/Account.java AbstractAccountAuthenticator ... frameworks/base/core/java/android/accounts/AbstractAccountAuthenticator.java IAccountManager.aidl ........... frameworks/base/core/java/android/accounts/IAccountManager.aidl IAccountAuthenticator.aidl ..... frameworks/base/core/java/android/accounts/IAccountAuthenticator.aidl AccountManagerService .......... frameworks/base/services/core/java/com/android/server/accounts/AccountManagerService.java AccountsDb ..................... frameworks/base/services/core/java/com/android/server/accounts/AccountsDb.java TokenCache ..................... frameworks/base/services/core/java/com/android/server/accounts/TokenCache.java AccountAuthenticatorCache ...... frameworks/base/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java32.1.2 架构图
32.1.3 AccountManager — 应用入口
通过Context.getSystemService(Context.ACCOUNT_SERVICE)获取AccountManager;注解为@SystemService(Context.ACCOUNT_SERVICE)。
源码:frameworks/base/core/java/android/accounts/AccountManager.java
该类同时提供同步、异步接口。绝大多数方法返回AccountManagerFuture<Bundle>,可搭配回调,也可阻塞调用getResult()。
| 方法 | 用途 | 返回值 |
|---|---|---|
| getAccounts() | 获取设备上全部账户 | Account[] |
| getAccountsByType(type) | 获取指定类型账户 | Account[] |
| getAccountsByTypeAndFeatures(...) | 按类型、特性过滤账户 | Future |
| addAccount(type, ...) | 拉起 UI 添加新账户 | Future(携带 KEY_INTENT 的 Bundle) |
| removeAccount(account, ...) | 删除账户 | Future |
| getAuthToken(account, type, ...) | 获取身份令牌 | Future(携带 KEY_AUTHTOKEN 的 Bundle) |
| invalidateAuthToken(type, token) | 作废缓存令牌 | void |
| setAuthToken(account, type, token) | 手动设置令牌 | void |
| getPassword(account) | 读取账户密码(调用方受限) | String |
| setPassword(account, password) | 设置账户密码 | void |
| addAccountExplicitly(account, password, extras) | 无 UI 方式添加账户 | boolean |
| setUserData(account, key, value) | 存储账户键值对数据 | void |
| getUserData(account, key) | 读取账户键值对数据 | String |
| addOnAccountsUpdatedListener(...) | 注册账户变更监听 | void |
32.1.4 Account 数据模型
Account是简单值类型,包含两个字段:
// 取自 frameworks/base/core/java/android/accounts/Account.java public class Account implements Parcelable { public final String name; // 例如 "user@gmail.com" public final String type; // 例如 "com.google" }type是关键标识,将账户与对应认证器绑定。该值必须与认证器 XML 元数据内android:accountType属性保持一致。
关联类型:
| 类 | 用途 |
|---|---|
| Account | 账户名称 + 类型组合 |
| AccountAndUser | 账户 + 用户 ID(内部使用) |
| AuthenticatorDescription | 已注册认证器的元数据 |
| AccountAuthenticatorResponse | 向服务返回结果的回调通道 |
32.1.5 账户可见性
Android 8.0 + 引入账户可见性机制,管控应用可以看到哪些账户。替代旧版粗放的GET_ACCOUNTS权限模型。
| 可见性等级 | 常量 | 含义 |
|---|---|---|
| 不可见 | VISIBILITY_NOT_VISIBLE | 应用看不到该账户 |
| 用户托管可见 | VISIBILITY_USER_MANAGED_VISIBLE | 用户授权后才可见 |
| 可见 | VISIBILITY_VISIBLE | 对该应用始终可见 |
| 未定义 | VISIBILITY_UNDEFINED | 回退到认证器默认策略 |
// 设置指定账户+包名的可见性 accountManager.setAccountVisibility( account, "com.example.app", AccountManager.VISIBILITY_VISIBLE ); // 查询可见性 int visibility = accountManager.getAccountVisibility( account, "com.example.app" );
32.1.6 AccountManagerFuture — 异步结果模式
绝大多数AccountManager方法返回AccountManagerFuture<Bundle>,封装一次异步操作。
源码:frameworks/base/core/java/android/accounts/AccountManagerFuture.javaframeworks/base/core/java/android/accounts/AccountManagerCallback.java
// 回调方式使用 accountManager.getAuthToken( account, "oauth2:email", null, activity, new AccountManagerCallback<Bundle>() { @Override public void run(AccountManagerFuture<Bundle> future) { try { Bundle result = future.getResult(); String token = result.getString(AccountManager.KEY_AUTHTOKEN); // 使用令牌 } catch (AuthenticatorException | OperationCanceledException | IOException e) { // 处理异常 } } }, handler ); // 阻塞调用(禁止在UI线程执行) Bundle result = accountManager.getAuthToken( account, "oauth2:email", null, activity, null, // 不使用回调 null // 不使用handler ).getResult(); // 阻塞直至完成 String token = result.getString(AccountManager.KEY_AUTHTOKEN);结果 Bundle 使用如下标准常量键:
| 常量键 | 类型 | 说明 |
|---|---|---|
| KEY_ACCOUNT_NAME | String | 账户名 |
| KEY_ACCOUNT_TYPE | String | 账户类型 |
| KEY_AUTHTOKEN | String | 身份令牌 |
| KEY_INTENT | Intent | 需要拉起用户交互的 UI |
| KEY_BOOLEAN_RESULT | boolean | 布尔返回结果(hasFeatures 等) |
| KEY_ERROR_CODE | int | 认证器返回错误码 |
| KEY_ERROR_MESSAGE | String | 认证器返回错误信息 |
| KEY_USERDATA | Bundle | 账户附属用户数据 |
32.1.7 账户变更监听器
应用可注册监听,接收账户变更通知:
// 注册账户变更监听 accountManager.addOnAccountsUpdatedListener( new OnAccountsUpdateListener() { @Override public void onAccountsUpdated(Account[] accounts) { // 账户新增、删除、重命名时触发 for (Account account : accounts) { Log.i(TAG, "Account: " + account.name + " (" + account.type + ")"); } } }, handler, // 回调执行Handler true // updateImmediately — 立即回调返回当前账户列表 ); // 按类型过滤的监听器(API 26+) accountManager.addOnAccountsUpdatedListener( listener, handler, true, new String[]{"com.google"} // 仅接收Google账户变更通知 );内部实现:AccountManagerService为每个用户维护RemoteCallbackList<IAccountManagerResponse>,账户发生变更时分发更新。
32.1.8 账户 Intent 广播
账户新增、删除、修改时,AccountManagerService发送如下广播:
| 广播常量 | 触发条件 |
|---|---|
| AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION | 账户新增 / 删除 |
| AccountManager.ACTION_ACCOUNT_REMOVED | 特定账户被删除(定向广播) |
| AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED | 账户可见性变更 |
应用(尤其同步适配器)依靠广播感知账户变化,无需轮询。
32.2 AccountManagerService
32.2.1 服务注册
AccountManagerService是 system_server 启动阶段初始化的系统服务,实现IAccountManagerAIDL 接口。
源码:frameworks/base/services/core/java/com/android/server/accounts/AccountManagerService.java
作为SystemService生命周期组件完成注册:
// SystemServer中简化的注册流程 public final class AccountManagerService extends IAccountManager.Stub implements RegisteredServicesCacheListener<AuthenticatorDescription> { public static class Lifecycle extends SystemService { private AccountManagerService mService; @Override public void onStart() { mService = new AccountManagerService(getContext()); publishBinderService(Context.ACCOUNT_SERVICE, mService); } @Override public void onUserUnlocking(TargetUser user) { mService.onUserUnlocked(user); } } }32.2.2 按用户隔离的账户存储
AccountManagerService为 Android 每一个用户维护独立账户数据。每个用户下存在两套数据库:
DE(设备加密)与 CE(凭证加密)存储区分遵循 Android Direct Boot 直接启动模型:
| 存储 | 可用时机 | 存储内容 |
|---|---|---|
| DE(accounts_de.db) | 设备开机完成后 | 账户名、类型、授权、可见性 |
| CE(accounts_ce.db) | 用户解锁之后 | 密码、身份令牌、用户附属数据 |
源码:frameworks/base/services/core/java/com/android/server/accounts/AccountsDb.java
32.2.3 AccountsDb 数据表结构
AccountsDb封装 SQLite 数据库操作。核心表:
源码:frameworks/base/services/core/java/com/android/server/accounts/AccountsDb.java
CE 数据库表:
| 表 | 字段 | 用途 |
|---|---|---|
| accounts | _id, name, type, password, previous_name, last_password_entry_time_millis_epoch | 账户核心存储 |
| authtokens | _id, accounts_id, type, authtoken | 缓存身份令牌 |
| extras | _id, accounts_id, key, value | 账户键值对附属数据 |
DE 数据库表:
| 表 | 字段 | 用途 |
|---|---|---|
| accounts | _id, name, type | 账户列表(不含凭证) |
| grants | accounts_id, auth_token_type, uid | 按 UID 划分的令牌访问授权 |
| visibility | accounts_id, _package, value | 按包名的账户可见性 |
| shared_accounts | _id, name, type | 跨配置文件共享账户 |
| meta | key, value | 服务元数据 |
| debug_table | 各类调试字段 | 调试、审计信息 |
32.2.4 UserAccounts — 用户状态对象
AccountManagerService内部为每一个用户持有UserAccounts对象:
// 取自AccountManagerService.java简化代码 static class UserAccounts { final int userId; final AccountsDb accountsDb; // 数据库访问对象 final HashMap<Pair<Pair<Account, String>, Integer>, /* ... */> credentialsPermissionNotificationIds; // 待处理权限通知 final HashMap<Account, HashMap<String, String>> userDataC