💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
**SystemServer.java::ServerThread.run** ~~~ ...... //注册AccountManagerService到ServiceManager,服务名为“account” ServiceManager.addService(Context.ACCOUNT_SERVICE, newAccountManagerService(context)); ~~~ 其构造函数的代码如下: **AccountManagerService.java::AccountManagerService** ~~~ public AccountManagerService(Context context) { //调用另外一个构造函数,其第三个参数将构造一个AccountAuthenticatorCache对象,它是 //什么呢?见下文分析 this(context,context.getPackageManager(), new AccountAuthenticatorCache(context)); } ~~~ 在AccountManagerService构造函数中创建了一个AccountAuthenticatorCache对象,它是什么?来看下文。 1. AccountAuthenticatorCache分析 AccountAuthenticatorCache是Android平台中账户验证服务(Account AuthenticatorService,AAS)的管理中心。而AAS则由应用程序通过在AndroidManifest.xml中输出符合指定要求的Service信息而来。稍后读者将看到这些要求的具体格式。 先来看AccountAuthenticatorCache的派生关系,如图8-3所示。 :-: ![](http://img.blog.csdn.net/20150803131407976?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图8-3 AccountAuthenticatorCache类图 由图8-3可知: - AccountAuthenticatorCache从RegisteredServicesCache<AuthenticatorDescription>派生。RegisteredServicesCache是一个模板类,专门用于管理系统中指定Service的信息收集和更新,而具体是哪些Service由RegisteredServicesCache构造时的参数指定。AccountAuthenticatorCache对外输出由RegisteredServicesCache模板参数指定的类的实例。在图8-3中应该就是AuthenticatorDescription。 - AuthenticatorDescription继承了Parcelable接口,这代表它可以跨Binder传递。该类描述了AAS相关的信息。 - AccountAuthenticatorCache实现了IAccountAuthenticatorCache接口。这个接口供外部调用者使用以获取AAS的信息。 下面看AccountAuthenticatorCache的创建,其相关代码如下: **AccountAuthenticatorCache.java::AccountAuthenticatorCache** ~~~ public AccountAuthenticatorCache(Context context){ /* ACTION_AUTHENTICATOR_INTENT值为"android.accounts.AccountAuthenticator" AUTHENTICATOR_META_DATA_NAME值为"android.accounts.AccountAuthenticator" AUTHENTICATOR_ATTRIBUTES_NAME值为"account-authenticator" */ super(context, AccountManager.ACTION_AUTHENTICATOR_INTENT, AccountManager.AUTHENTICATOR_META_DATA_NAME, AccountManager.AUTHENTICATOR_ATTRIBUTES_NAME, sSerializer); } ~~~ AccountAuthenticatorCache调用在其基类RegisteredServicesCache的构造函数时,传递了3个字符串参数,这3个参数用于控制RegisteredServicesCache从PackageManagerService获取哪些Service的信息。 (1) RegisteredServicesCache分析 **RegisteredServicesCache.java::RegisteredServicesCache** ~~~ public RegisteredServicesCache(Context context,String interfaceName, StringmetaDataName, String attributeName, XmlSerializerAndParser<V>serializerAndParser) { mContext= context; //保存传递进来的参数 mInterfaceName = interfaceName; mMetaDataName = metaDataName; mAttributesName = attributeName; mSerializerAndParser = serializerAndParser; FiledataDir = Environment.getDataDirectory(); FilesystemDir = new File(dataDir, "system"); //syncDir指向/data/system/registered_service目录 FilesyncDir = new File(systemDir, "registered_services"); //下面这个文件指向syncDir目录下的android.accounts.AccountAuthenticator.xml mPersistentServicesFile = new AtomicFile(new File(syncDir, interfaceName+ ".xml")); //生成服务信息 generateServicesMap(); finalBroadcastReceiver receiver = new BroadcastReceiver() { public void onReceive(Context context1, Intent intent) { generateServicesMap(); } }; //注册Package安装、卸载和更新等广播监听者 mReceiver = new AtomicReference<BroadcastReceiver>(receiver); IntentFilter intentFilter = newIntentFilter(); intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addDataScheme("package"); mContext.registerReceiver(receiver, intentFilter); IntentFilter sdFilter = new IntentFilter(); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(receiver, sdFilter); } ~~~ 由以上代码可知: - 成员变量mPersistentServicesFile指向/data/system/registered_service/目录下的一个文件,该文件保存了以前获取的对应Service的信息。就AccountAuthenticator而言,mPersistentServicesFile指向该目录的android.accounts.AccountAuthenticator.xml文件。 - 由于RegisteredServicesCache管理的是系统中指定Service的信息,当系统中有Package安装、卸载或更新时,RegisteredServicesCache也需要对应更新自己的信息,因为有些Service可能会随着APK被删除而不复存在。 generateServiceMap函数将获取指定的Service信息,其代码如下: **RegisteredServicesCache.java::generateServicesMap** ~~~ void generateServicesMap() { //获取PackageManager接口,用来和PackageManagerService交互 PackageManager pm = mContext.getPackageManager(); ArrayList<ServiceInfo<V>> serviceInfos = newArrayList<ServiceInfo<V>>(); /* 在本例中,查询PKMS中满足Intent Action为"android.accounts.AccountAuthenticator" 的服务信息。由以下代码可知,这些信息指的是Service中声明的MetaData信息 */ List<ResolveInfo> resolveInfos = pm.queryIntentServices( new Intent(mInterfaceName),PackageManager.GET_META_DATA); for(ResolveInfo resolveInfo : resolveInfos) { try { /* 调用parserServiceInfo函数解析从PKMS中获得的MetaData信息,该函数 返回的是一个模板类对象。就本例而言,这个函数返回一个 ServiceInfo<AccountAuthenticator>类型的对象 */ ServiceInfo<V> info = parseServiceInfo(resolveInfo); serviceInfos.add(info); } } synchronized (mServicesLock) { if(mPersistentServices == null) readPersistentServicesLocked(); mServices = Maps.newHashMap(); StringBuilder changes = new StringBuilder(); ......//检查mPersistentServices保存的服务信息和当前从PKMS中取出来的PKMS //信息,判断是否有变化,如果有变化,需要通知监听者。读者可自行阅读这段代码, //注意其中uid的作用 mPersistentServicesFileDidNotExist = false; } } ~~~ 接下来解析Service的parseServiceInfo函数。 (2) parseServiceInfo函数分析 **RegisteredServicesCache.java::parseServiceInfo** ~~~ private ServiceInfo<V>parseServiceInfo(ResolveInfo service) throws XmlPullParserException, IOException { android.content.pm.ServiceInfo si = service.serviceInfo; ComponentName componentName = new ComponentName(si.packageName, si.name); PackageManager pm = mContext.getPackageManager(); XmlResourceParser parser = null; try { //解析MetaData信息 parser = si.loadXmlMetaData(pm, mMetaDataName); AttributeSet attrs = Xml.asAttributeSet(parser); inttype; ...... StringnodeName = parser.getName(); //调用子类实现的parseServiceAttributes得到一个真实的对象,在本例中它是 //AuthenticatorDescription。注意,传递给parseServiceAttributes的第一个 //参数代表MetaData中的resource信息。详细内容见下文的图例 V v=parseServiceAttributes( pm.getResourcesForApplication(si.applicationInfo), si.packageName, attrs); finalandroid.content.pm.ServiceInfo serviceInfo = service.serviceInfo; finalApplicationInfo applicationInfo = serviceInfo.applicationInfo; finalint uid = applicationInfo.uid; returnnew ServiceInfo<V>(v, componentName, uid); } ...... finally { if (parser != null) parser.close(); } } ~~~ parseServiceInfo将解析Service中的MetaData信息,然后调用子类实现的parseServiceAttributes函数,以获取特定类型Service的信息。 下面通过实例向读者展示最终的解析结果。 (3) AccountAuthenticatorCache分析总结 在Email应用的AndroidManifest.xml中定义了一个AAS,如图8-4所示。 :-: ![](http://img.blog.csdn.net/20150803131422504?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图8-4 Email AAS定义 由图8-4可知,在Email中这个Service对应为EasAuthenticatorService,其Intent匹配的Action为“android.accounts.AccountAuthenticator”,其MetaData的name为“android.accounts.AccountAuthenticator”,而MetaData的具体信息保存在resource资源中,在本例中,它指向另外一个xml文件,即eas_authenticator.xml,此文件的内容如图8-5所示。 :-: ![](http://img.blog.csdn.net/20150803131437028?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图8-5 eas_authenticator.xml的内容 图8-5为Email中eas_authenticator.xml的内容。这个xml中的内容是有严格要求的,其中: - accountType标签用于指定账户类型(账户类型和具体应用有关,Android并未规定账户的类型)。 - icon、smallIcon、label和accountPreferences等用于界面显示。例如,当需要用户输入账户信息时,系统会弹出一个Activity,上述几个标签就用于界面显示。详细情况可阅读SDK文档AbstractAccountAuthenticator的说明。 而android.accounts.AccountAuthenticator.xml的内容如图8-6所示。 :-: ![](http://img.blog.csdn.net/20150803131452038?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图8-6 android.accounts.AccountAuthenticator.xml的内容 由图8-6可知,笔者的测试机器上有3个AAS服务,其中同一个uid有两个服务(即uid为10015对应的两个Service)。 * * * * * **提示**:uid是在为PackageManagerService解析APK文件时赋予APK的。读者不妨自行阅读frameworks/base/services/java/com/android/server/pm/Settings.java中的newUserIdLPw函数。 * * * * * 下面来看AccountManagerService的构造函数。 2. AccountManagerService构造函数分析 **AccountManagerService.java::AccountManagerService** ~~~ public AccountManagerService(Context context,PackageManager packageManager, IAccountAuthenticatorCache authenticatorCache) { mContext= context; mPackageManager = packageManager; synchronized (mCacheLock) { //此数据库文件对应为/data/system/accounts.db mOpenHelper = new DatabaseHelper(mContext); } mMessageThread = new HandlerThread("AccountManagerService"); mMessageThread.start(); mMessageHandler = new MessageHandler(mMessageThread.getLooper()); mAuthenticatorCache = authenticatorCache; //为AccountAuthenticatorCache设置一个监听者,一旦AAS服务发生变化, //AccountManagerService需要做对应处理 mAuthenticatorCache.setListener(this, null /* Handler */); sThis.set(this); //监听ACTION_PACKAGE_REMOVED广播 IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addDataScheme("package"); mContext.registerReceiver(new BroadcastReceiver() { publicvoid onReceive(Context context1, Intent intent) { purgeOldGrants(); } },intentFilter); /* accounts.db数据库中有一个grants表,用于存储授权信息,该信息用于保存哪些Package 有权限获取账户信息。下面的函数将根据grants表中的数据查询PKMS,以判断这些 Package是否还存在。如果系统中已经不存在这些Package,则grants表需要更新 */ purgeOldGrants(); /* accounts.db中有一个accounts表,该表中存储了账户类型和账户名。其中,账户类型 就是AuthenticatorDescription中的accountType,它和具体应用有关。下面这个 函数将比较accounts表中的内容与AccountAuthenticatorCache中服务的信息,如果 AccountAuthenticatorCache已经不存在对应账户类型的服务,则需要删除accounts表 中的对应项 */ validateAccountsAndPopulateCache(); } ~~~ AccountManagerService的构造函数较简单,有兴趣的读者可自行研究以上代码中未详细分析的函数。下面将通过一个具体的例子来分析AccountManagerService的工作流程。