android账号与同步之发起同步

时间:2022-07-04 16:33:53

上一篇博文我介绍了账号与同步的同步实现过程,当中提供了一个工系统进程调用的服务,那么这个服务究竟是怎么被启动和使用的呢?这篇博文我就大体梳理一下启动过程。

事实上作为一个一般开发者,我们仅仅要知道要想知道被监听的ContentProvider有变动,首先那个ContentProvider必须使用ContentResolver.notifyChange(android.net.Uri,

android.database.ContentObserver, boolean)这种方法来通知我们。我们知道这种方法会通知监听这个ContentProvider的ContentObserver数据有变化,可是ContentObserver须要在一个执行这个的进程中注冊,假设这个进程死掉了ContentObserver也须要取消注冊监听,这样就没法监听了。只是值得注意的是,这个notifyChange方法还有另外一个作用,就是配合实现android的同步框架,通知SyncManager启动对应账号的同步。

ContentResolver.java

首先我们来看看ContentResolver的notifyChange源代码,例如以下:

public void notifyChange(Uri uri, ContentObserver observer) {

        notifyChange(uri, observer, true /* sync to network */);

    }

public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {

        notifyChange(uri, observer, syncToNetwork, UserHandle.getCallingUserId());

    }

public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork,

            int userHandle) {

        try {

            getContentService().notifyChange(

                    uri, observer == null ? null : observer.getContentObserver(),

                    observer != null && observer.deliverSelfNotifications(), syncToNetwork,

                    userHandle);

        } catch (RemoteException e) {

        }

    }

上面重载的三个notifyChange方法,终于调用的都是ContentService中的notifyChange方法,getContentService()方法例如以下:

    public static IContentService getContentService() {

        if (sContentService != null) {

            return sContentService;

        }

        IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME);

        if (false) Log.v("ContentService", "default service binder = " + b);

        sContentService = IContentService.Stub.asInterface(b);

        if (false) Log.v("ContentService", "default service = " + sContentService);

        return sContentService;

    }

ContentService.java

ContentService是对存根类IContentService.Stub的实现,它提供一系列数据同步及数据訪问等相关的操作,源代码例如以下:

public final class ContentService extends IContentService.Stub

此类中的两个重载的notifyChange方法例如以下:

public void notifyChange(Uri uri, IContentObserver observer,

            boolean observerWantsSelfNotifications, boolean syncToNetwork) {

        notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork,

                UserHandle.getCallingUserId());

    }

@Override

    public void notifyChange(Uri uri, IContentObserver observer,

            boolean observerWantsSelfNotifications, boolean syncToNetwork,

            int userHandle) {

            ...

     最重要的一句,就是启动ContentObserver的onChange方法

            oc.mObserver.onChange(oc.mSelfChange, uri);

     ...

最重要的还有一句,就是启动同步

            if (syncToNetwork) {

                SyncManager syncManager = getSyncManager();

                if (syncManager != null) {

                    syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid,

                            uri.getAuthority());

                }

            }

        } finally {

            restoreCallingIdentity(identityToken);

        }

    }

//获取SyncManager 的方法

    private SyncManager getSyncManager() {

        if (SystemProperties.getBoolean("config.disable_network", false)) {

            return null;

        }

synchronized(mSyncManagerLock) {

            try {

                // Try to create the SyncManager, return null if it fails (e.g. the disk is full).

                if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest);

            } catch (SQLiteException e) {

                Log.e(TAG, "Can't create SyncManager", e);

            }

            return mSyncManager;

        }

    }

SyncManager.java

这是一个同步机制中最核心的类,承载了基本的功能实现,本人仅仅大体介绍一下主要代码,以求打通整个流程。首先来看上面那个类调用的方法scheduleLocalSync:

public void scheduleLocalSync(Account account, int userId, int reason, String authority) {

        final Bundle extras = new Bundle();

        extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);

        scheduleSync(account, userId, reason, authority, extras,

                LOCAL_SYNC_DELAY /* earliest run time */,

                2 * LOCAL_SYNC_DELAY /* latest sync time. */,

                false /* onlyThoseWithUnkownSyncableState */);

    }

scheduleLocalSync方法主要调用了scheduleSync方法,其大体内容例如以下:

public void scheduleSync(Account requestedAccount, int userId, int reason,

            String requestedAuthority, Bundle extras, long beforeRuntimeMillis,

            long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {

        boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);

final boolean backgroundDataUsageAllowed = !mBootCompleted ||

                getConnectivityManager().getBackgroundDataSetting();

if (extras == null) {

            extras = new Bundle();

        }

        if (isLoggable) {

            Log.d(TAG, "one-time sync for: " + requestedAccount + " " + extras.toString() + " "

                    + requestedAuthority);

        }

//假设是加速模式则把延迟时间设置为-1,runtimeMillis在较早的版本号中是叫做delay的,就是当你调用这种方法后多久启动同步任务。

        Boolean expedited = extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);

        if (expedited) {

            runtimeMillis = -1; // this means schedule at the front of the queue

        }

//获取手机中全部加入过的账号信息

        AccountAndUser[] accounts;

        if (requestedAccount != null && userId != UserHandle.USER_ALL) {

            accounts = new AccountAndUser[] { new AccountAndUser(requestedAccount, userId) };

        } else {

            // if the accounts aren't configured yet then we can't support an account-less

            // sync request

            accounts = mRunningAccounts;

            if (accounts.length == 0) {

                if (isLoggable) {

                    Log.v(TAG, "scheduleSync: no accounts configured, dropping");

                }

                return;

            }

        }

//

        final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);

        final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);

        if (manualSync) {

            extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);

            extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);

        }

        final boolean ignoreSettings =

                extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);

int source;

        if (uploadOnly) {

            source = SyncStorageEngine.SOURCE_LOCAL;

        } else if (manualSync) {

            source = SyncStorageEngine.SOURCE_USER;

        } else if (requestedAuthority == null) {

            source = SyncStorageEngine.SOURCE_POLL;

        } else {

            // this isn't strictly server, since arbitrary callers can (and do) request

            // a non-forced two-way sync on a specific url

            source = SyncStorageEngine.SOURCE_SERVER;

        }

for (AccountAndUser account : accounts) {

            // Compile a list of authorities that have sync adapters. For each authority sync each account that matches a sync adapter.

            final HashSet<String> syncableAuthorities = new HashSet<String>();

            for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapter :

                    mSyncAdapters.getAllServices(account.userId)) {

                syncableAuthorities.add(syncAdapter.type.authority);

            }

// if the url was specified then replace the list of authorities with just this authority or clear it if this authority isn't syncable

            if (requestedAuthority != null) {

                final boolean hasSyncAdapter = syncableAuthorities.contains(requestedAuthority);

                syncableAuthorities.clear();

                if (hasSyncAdapter) syncableAuthorities.add(requestedAuthority);

            }

for (String authority : syncableAuthorities) {

  //account账号是否声明同步authority

                int isSyncable = getIsSyncable(account.account, account.userId,

                        authority);

                if (isSyncable == 0) {

                    continue;

                }

  //一系列的推断,排除一起异常的情况

                final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;

                syncAdapterInfo = mSyncAdapters.getServiceInfo(

                        SyncAdapterType.newKey(authority, account.account.type), account.userId);

                if (syncAdapterInfo == null) {

                    continue;

                }

                final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();

                final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();

                if (isSyncable < 0 && isAlwaysSyncable) {

                    mSyncStorageEngine.setIsSyncable(account.account, account.userId, authority, 1);

                    isSyncable = 1;

                }

                if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) {

                    continue;

                }

                if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {

                    continue;

                }

// always allow if the isSyncable state is unknown

                boolean syncAllowed =

                        (isSyncable < 0)

                        || ignoreSettings

                        || (backgroundDataUsageAllowed

                                && mSyncStorageEngine.getMasterSyncAutomatically(account.userId)

                                && mSyncStorageEngine.getSyncAutomatically(account.account,

                                        account.userId, authority));

                if (!syncAllowed) {

                    if (isLoggable) {

                        Log.d(TAG, "scheduleSync: sync of " + account + ", " + authority

                                + " is not allowed, dropping request");

                    }

                    continue;

                }

//最后进入两种须要通知同步的情况,都调用scheduleSyncOperation方法实现

                Pair<Long, Long> backoff = mSyncStorageEngine

                        .getBackoff(account.account, account.userId, authority);

                long delayUntil = mSyncStorageEngine.getDelayUntilTime(account.account,

                        account.userId, authority);

                final long backoffTime = backoff != null ? backoff.first : 0;

                if (isSyncable < 0) {

                    // Initialisation sync.

                    Bundle newExtras = new Bundle();

                    newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);

                    if (isLoggable) {

                        Log.v(TAG, "schedule initialisation Sync:"

                                + ", delay until " + delayUntil

                                + ", run by " + 0

                                + ", source " + source

                                + ", account " + account

                                + ", authority " + authority

                                + ", extras " + newExtras);

                    }

    

                    scheduleSyncOperation(

                            new SyncOperation(account.account, account.userId, reason, source,

                                    authority, newExtras, 0 /* immediate */, 0 /* No flex time*/,

                                    backoffTime, delayUntil, allowParallelSyncs));

                }

                if (!onlyThoseWithUnkownSyncableState) {

                    if (isLoggable) {

                        Log.v(TAG, "scheduleSync:"

                                + " delay until " + delayUntil

                                + " run by " + runtimeMillis

                                + " flex " + beforeRuntimeMillis

                                + ", source " + source

                                + ", account " + account

                                + ", authority " + authority

                                + ", extras " + extras);

                    }

                    scheduleSyncOperation(

                            new SyncOperation(account.account, account.userId, reason, source,

                                    authority, extras, runtimeMillis, beforeRuntimeMillis,

                                    backoffTime, delayUntil, allowParallelSyncs));

                }

            }

        }

    }

//此方法主要做两件是,一是把要同步的操作加入到队列中,二是发消息

 public void scheduleSyncOperation(SyncOperation syncOperation) {

        boolean queueChanged;

        synchronized (mSyncQueue) {

            queueChanged = mSyncQueue.add(syncOperation);

        }

if (queueChanged) {

            if (Log.isLoggable(TAG, Log.VERBOSE)) {

                Log.v(TAG, "scheduleSyncOperation: enqueued " + syncOperation);

            }

            sendCheckAlarmsMessage();

        } else {

            if (Log.isLoggable(TAG, Log.VERBOSE)) {

                Log.v(TAG, "scheduleSyncOperation: dropping duplicate sync operation "

                        + syncOperation);

            }

        }

    }

//发出MESSAGE_CHECK_ALARMS消息 

    private void sendCheckAlarmsMessage() {

        if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "sending MESSAGE_CHECK_ALARMS");

        mSyncHandler.removeMessages(SyncHandler.MESSAGE_CHECK_ALARMS);

        mSyncHandler.sendEmptyMessage(SyncHandler.MESSAGE_CHECK_ALARMS);

    }

//接收消息并处理

  @Override

        public void handleMessage(Message msg) {

            if (tryEnqueueMessageUntilReadyToRun(msg)) {

                return;

            }

switch (msg.what) {

                    case SyncHandler.MESSAGE_CANCEL: {

                     ...

                    case SyncHandler.MESSAGE_SYNC_FINISHED:

                     ...

                    case SyncHandler.MESSAGE_SERVICE_CONNECTED: {

                        ServiceConnectionData msgData = (ServiceConnectionData)msg.obj;

                        if (Log.isLoggable(TAG, Log.VERBOSE)) {

                            Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CONNECTED: "

                                    + msgData.activeSyncContext);

                        }

                        // check that this isn't an old message

                        if (isSyncStillActive(msgData.activeSyncContext)) {

                            runBoundToSyncAdapter(msgData.activeSyncContext, msgData.syncAdapter);

                        }

                        break;

                    }

case SyncHandler.MESSAGE_SERVICE_DISCONNECTED: {

                     ...

case SyncHandler.MESSAGE_SYNC_ALARM: {

                        boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);

                        if (isLoggable) {

                            Log.v(TAG, "handleSyncHandlerMessage: MESSAGE_SYNC_ALARM");

                        }

                        mAlarmScheduleTime = null;

                        try {

                            nextPendingSyncTime = maybeStartNextSyncLocked();

                        } finally {

                            mHandleAlarmWakeLock.release();

                        }

                        break;

                    }

      //须要检查时钟任务,有须要通知的同步操作

                    case SyncHandler.MESSAGE_CHECK_ALARMS:

                        if (Log.isLoggable(TAG, Log.VERBOSE)) {

                            Log.v(TAG, "handleSyncHandlerMessage: MESSAGE_CHECK_ALARMS");

                        }

                        nextPendingSyncTime = maybeStartNextSyncLocked();

                        break;

                }

            } finally {

                manageSyncNotificationLocked();

                manageSyncAlarmLocked(earliestFuturePollTime, nextPendingSyncTime);

                mSyncTimeTracker.update();

                mSyncManagerWakeLock.release();

            }

        }

//检查可能有下一个通知操作

  private long maybeStartNextSyncLocked() {

...一堆的推断

for (int i = 0, N = operations.size(); i < N; i++) {

...一堆的推断

// If the next run time is in the future, even given the flexible scheduling, return the time.

                    if (op.effectiveRunTime - op.flexTime > now) {

                        if (nextReadyToRunTime > op.effectiveRunTime) {

                            nextReadyToRunTime = op.effectiveRunTime;

                        }

                        if (isLoggable) {

                            Log.v(TAG, "    Dropping sync operation: Sync too far in future.");

                        }

                        continue;

                    }

...一堆的推断

if (toReschedule != null) {

                    runSyncFinishedOrCanceledLocked(null, toReschedule);

                    scheduleSyncOperation(toReschedule.mSyncOperation);

                }

                synchronized (mSyncQueue) {

                    mSyncQueue.remove(candidate);

                }

  

                dispatchSyncOperation(candidate);

            }

return nextReadyToRunTime;

     }

        //正式分发通知同步操作

        private boolean dispatchSyncOperation(SyncOperation op) {

            if (Log.isLoggable(TAG, Log.VERBOSE)) {

                Log.v(TAG, "dispatchSyncOperation: we are going to sync " + op);

                Log.v(TAG, "num active syncs: " + mActiveSyncContexts.size());

                for (ActiveSyncContext syncContext : mActiveSyncContexts) {

                    Log.v(TAG, syncContext.toString());

                }

            }

// connect to the sync adapter

            SyncAdapterType syncAdapterType = SyncAdapterType.newKey(op.authority, op.account.type);

            final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;

            syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, op.userId);

            if (syncAdapterInfo == null) {

                Log.d(TAG, "can't find a sync adapter for " + syncAdapterType

                        + ", removing settings for it");

                mSyncStorageEngine.removeAuthority(op.account, op.userId, op.authority);

                return false;

            }

     //一个SyncManager的内部类

            ActiveSyncContext activeSyncContext =

                    new ActiveSyncContext(op, insertStartSyncEvent(op), syncAdapterInfo.uid);

            activeSyncContext.mSyncInfo = mSyncStorageEngine.addActiveSync(activeSyncContext);

            mActiveSyncContexts.add(activeSyncContext);

            if (Log.isLoggable(TAG, Log.VERBOSE)) {

                Log.v(TAG, "dispatchSyncOperation: starting " + activeSyncContext);

            }

     //绑定服务端

            if (!activeSyncContext.bindToSyncAdapter(syncAdapterInfo, op.userId)) {

                Log.e(TAG, "Bind attempt failed to " + syncAdapterInfo);

                closeActiveSyncContext(activeSyncContext);

                return false;

            }

return true;

        }

ActiveSyncContext.java

ActiveSyncContext是SyncManager的内部类,它实现了ServiceConnection,当中的两个重要的方法例如以下:

boolean bindToSyncAdapter(RegisteredServicesCache.ServiceInfo info, int userId) {

            if (Log.isLoggable(TAG, Log.VERBOSE)) {

                Log.d(TAG, "bindToSyncAdapter: " + info.componentName + ", connection " + this);

            }

            Intent intent = new Intent();

     //还记得上一篇博文中的这个Action吗?android.content.SyncAdapter

            intent.setAction("android.content.SyncAdapter");

            intent.setComponent(info.componentName);

            intent.putExtra(Intent.EXTRA_CLIENT_LABEL,

                    com.android.internal.R.string.sync_binding_label);

            intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(

                    mContext, 0, new Intent(Settings.ACTION_SYNC_SETTINGS), 0,

                    null, new UserHandle(userId)));

            mBound = true;

            final boolean bindResult = mContext.bindServiceAsUser(intent, this,

                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND

                    | Context.BIND_ALLOW_OOM_MANAGEMENT,

                    new UserHandle(mSyncOperation.userId));

            if (!bindResult) {

                mBound = false;

            }

            return bindResult;

        }

public void onServiceConnected(ComponentName name, IBinder service) {

            Message msg = mSyncHandler.obtainMessage();

            msg.what = SyncHandler.MESSAGE_SERVICE_CONNECTED;

            msg.obj = new ServiceConnectionData(this, ISyncAdapter.Stub.asInterface(service));

            mSyncHandler.sendMessage(msg);

        }

//在上面的接收MESSAGE_SERVICE_CONNECTED消息后,运行runBoundToSyncAdapter

private void runBoundToSyncAdapter(final ActiveSyncContext activeSyncContext,

              ISyncAdapter syncAdapter) {

            activeSyncContext.mSyncAdapter = syncAdapter;

            final SyncOperation syncOperation = activeSyncContext.mSyncOperation;

            try {

                activeSyncContext.mIsLinkedToDeath = true;

                syncAdapter.asBinder().linkToDeath(activeSyncContext, 0);

  //还记得上一篇博文中有关startSync的介绍吗?

                syncAdapter.startSync(activeSyncContext, syncOperation.authority,

                        syncOperation.account, syncOperation.extras);

            } catch (RemoteException remoteExc) {

                Log.d(TAG, "maybeStartNextSync: caught a RemoteException, rescheduling", remoteExc);

                closeActiveSyncContext(activeSyncContext);

                increaseBackoffSetting(syncOperation);

                scheduleSyncOperation(new SyncOperation(syncOperation));

            } catch (RuntimeException exc) {

                closeActiveSyncContext(activeSyncContext);

                Log.e(TAG, "Caught RuntimeException while starting the sync " + syncOperation, exc);

            }

        }

注意,本博文仅仅是简单地抽取了notifyChange分支的流程,给大家看,有兴趣的童鞋能够研究一下requestSync流程。