第 32 章:账户与同步框架
2026/8/22 12:01:50 网站建设 项目流程

Android 的账户与同步框架提供两个紧耦合的子系统:AccountManager用于凭证存储与身份令牌管理;SyncManager用于调度和执行后台数据同步。二者共同构成所有与远端服务器同步数据的应用的底层支撑,涵盖邮件、联系人、企业 MDM 以及第三方云服务。

本章完整梳理整套架构:从面向应用的AccountManagerContentResolver.requestSync()API,到 system_server 内部实现(AccountManagerServiceSyncManager),再到底层数据库存储以及与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.java

32.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_NAMEString账户名
KEY_ACCOUNT_TYPEString账户类型
KEY_AUTHTOKENString身份令牌
KEY_INTENTIntent需要拉起用户交互的 UI
KEY_BOOLEAN_RESULTboolean布尔返回结果(hasFeatures 等)
KEY_ERROR_CODEint认证器返回错误码
KEY_ERROR_MESSAGEString认证器返回错误信息
KEY_USERDATABundle账户附属用户数据

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账户列表(不含凭证)
grantsaccounts_id, auth_token_type, uid按 UID 划分的令牌访问授权
visibilityaccounts_id, _package, value按包名的账户可见性
shared_accounts_id, name, type跨配置文件共享账户
metakey, 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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询