android添加帳戶源碼淺析

  上篇粗略的分析android添加帳號的流程,本篇深刻的解析下執行步驟。先來看圖片,取自深刻理解android卷2:java

  上圖詳細的分析了addAccount的流程,下面咱們結合源碼來理解它android

一、addAccount:其實這裏省略了一步,應該是客戶端addAccount——>AddAccountSettings.addAccount——>AccountManager.addAccount。咱們看下setting是如何到AccountManager:git

private void addAccount(String accountType) {
    ......
        AccountManager.get(this).addAccount(
                accountType,
                null, /* authTokenType */
                null, /* requiredFeatures */
                addAccountOptions,
                null,
                mCallback,
                null /* handler */);
        mAddAccountCalled  = true;
    }
}

  代碼直白的告訴咱們就是去調用AccountManager.addAccount(好像是廢話哎),但咱們深刻看get函數發現另有玄機github

public static AccountManager get(Context context) {
        if (context == null) throw new IllegalArgumentException("context is null");
        return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
    } 

  而對於getSystemService(xxx)來講就是ContextImpl對應的註冊函數微信

registerService(ACCOUNT_SERVICE, new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
                    IAccountManager service = IAccountManager.Stub.asInterface(b);
                    return new AccountManager(ctx, service);
                }})
public AccountManager(Context context, IAccountManager service, Handler handler) {
        mContext = context;
        mService = service;
        mMainHandler = handler;
    }

  ok,也就是說AccountManager.get(this)去建立了一個包含IAccountManager.Stub.asInterface(實質爲AccountManagerService)的AccountManager.Proxy;這很重要下面會用到。app

2—五、這幾步都是在AccountManager.addAccount裏,代碼脈絡也很清晰就一塊兒解釋吧。ide

public AccountManagerFuture<Bundle> addAccount(final String accountType,
    ......
        return new AmsTask(activity, handler, callback) {
            public void doWork() throws RemoteException {
                mService.addAccount(mResponse, accountType, authTokenType,
                        requiredFeatures, activity != null, optionsIn);
            }
        }.start();
    }

  建立AmsTask並start,而start函數實質是去執行doWork函數,故這裏是去執行mService.addAccount。這裏須要注意的是mResponse,它是在new AmsTask時被建立函數

mResponse = new Response();

  Response是AmsTask的內部類且繼承自IAccountManagerResponse.Stub(重要)。源碼分析

6—十二、按流程是去執行mService.addAccount,上面分析到mService 爲AccountManagerService即AccountManagerService.addAccountui

  public void addAccount(final IAccountManagerResponse response, final String accountType,
    ......
        new Session(accounts, response, accountType, expectActivityLaunch,
                    true /* stripAuthTokenFromResult */) {
                @Override
                public void run() throws RemoteException {
                    mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
                            options);
                }
        ......
                }
            }.bind();
    ......

  能夠看到此函數中包含不少操做,咱們慢慢來剖析。

 private abstract class Session extends IAccountAuthenticatorResponse.Stub
           implements IBinder.DeathRecipient, ServiceConnection {
    ......

   Session的構造函數中初始化mResponse,看參數可知mResponse =AmsTask.mResponse

public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
    ......
    mResponse = response;
    ......
     IAccountManagerResponse response = mResponse;
    ......

  Session是AccountManagerService內部抽象類,繼承IAccountAuthenticatorResponse.Stub且實現ServiceConnection接口,這樣才能調用下面的bind(第8步)函數。

void bind() {
    ......
            if (!bindToAuthenticator(mAccountType)) {
                Log.d(TAG, "bind attempt failed for " + toDebugString());
                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
            }
        }
private boolean bindToAuthenticator(StringauthenticatorType) {
    //從mAuthenticatorCache中查詢知足指定類型的服務信息
   AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>
            authenticatorInfo =
             mAuthenticatorCache.getServiceInfo(
                           AuthenticatorDescription.newKey(authenticatorType));
   ......
    Intentintent = new Intent();
   intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
    //設置目標服務的ComponentName
   intent.setComponent(authenticatorInfo.componentName);
     //經過bindService啓動指定的服務,成功與否將經過第二個參數傳遞的
    //ServiceConnection接口返回
      if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
          ......
 }

  這裏分2步走:查詢系統獲得咱們要添加帳戶類型(微信、微博、淘寶,這裏用retme pocApp裏的代碼來解釋,不熟悉概念的看資料2)的authenticatorInfo;bindServiceAsUser去bind微信帳號的service(此service就是pocApp裏的AuthenticationService)。而此時pocApp的AuthenticationService執行onBind(第9步)

package com.example.android.samplesync.authenticator;

public IBinder onBind(Intent intent) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "getBinder()...  returning the AccountAuthenticator binder for intent "
                    + intent);
        }
        return mAuthenticator.getIBinder();
    }

  注意這裏返回的binder是mAuthenticator,而mAuthenticator是pocApp中的Authenticator(若是你不懂這些是什麼玩意,建議結合pocApp看資料2)。

class Authenticator extends AbstractAccountAuthenticator {

  AbstractAccountAuthenticator類中有內部類繼承

private class Transport extends IAccountAuthenticator.Stub {

  而在執行bindServiceAsUser後回去回調onServiceConnection函數(第10步),不清楚爲何要回調自行查資料。上面提到Session實現ServiceConnection接口,這裏直接調用Session.onServiceConnection。這裏的service就是onbind返回的Authenticator,故mAuthenticator = Authenticator

public void onServiceConnected(ComponentName name,IBinder service) {
   //獲得遠端AAS返回的IAccountAuthenticator接口,這個接口用於
  //AccountManagerService和該遠端AAS交互
   mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
    try {
           run();//調用匿名Session類實現的run函數,看第6步中的匿名類函數
     } ......
 }

  執行第11步 run

 public void run() throws RemoteException {
                    mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
                            options);
                }

  第12步mAuthenticator.addAccount就是pocApp中Authenticator.addAccount

1三、Authenticator.addAccount返回bundle。因爲pocApp沒有實現帳戶登錄,因此後面的流程走步下去了。但咱們看

[-->AbstractAccountAuthenticator.java::Transport:addAccount]發現其內部會調用

response.onResult(bundle);

   根據mAuthenticator.addAccount參數可知,response是IAccountAuthenticatorResponse類型就是上面的匿名Session類 。因此這裏執行的是Session.onResult

  public void onResult(Bundle result) {
            if (response != null) {
                try {
                ......
                        response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
                                "null bundle returned");
                    } else {
                        ......
                        response.onResult(result);
                    }
             ......
        }

1四、由第6步的Session構造函數可知 response就是AmsTask.mResponse,而AmsTask.mResponse =  new Response()這裏調用AmsTask內部類Response.onResult

 private class Response extends IAccountManagerResponse.Stub {
            public void onResult(Bundle bundle) {
                Intent intent = bundle.getParcelable(KEY_INTENT);
                if (intent != null && mActivity != null) {
                    // since the user provided an Activity we will silently start intents
                    // that we see
                    mActivity.startActivity(intent);
                    // leave the Future running to wait for the real response to this request
                } else if (bundle.getBoolean("retry")) {
                    try {
                        doWork();
                    } catch (RemoteException e) {
                        // this will only happen if the system process is dead, which means
                        // we will be dying ourselves
                    }
                } else {
                    set(bundle);
                }
            }

  這裏調用startActivity去啓動帳號登錄activity(launchAnyWhere bug)。源碼分析到此爲止嘞,可是期間涉及到的不少類咱們須要整理下,便於記憶和消化addAccount流程

 

 

  看到羅,addAccount就是上面這幾個類之間的操做。其實addAccount總結起來也很簡單,accountManager—>accountAuthenticator—>accountAuthenticatorRespone—>accountManagerRespone

 

 

參考資料:

一、[深刻理解Android卷二 全文-第八章]深刻理解ContentService和AccountManagerService

二、一步一步教你在 Android 裏建立本身的帳號系統(一)

三、https://github.com/retme7/launchAnyWhere_poc_by_retme_bug_7699048

相關文章
相關標籤/搜索