zoukankan      html  css  js  c++  java
  • android账号与同步之发起同步

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

    事实上作为一个一般开发者,我们仅仅要知道要想知道被监听的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流程。

  • 相关阅读:
    Android设计中的.9.png图片
    Socket原理
    word2vec中文类似词计算和聚类的使用说明及c语言源代码
    Scala之集合Collection
    使用C语言调用mysql数据库编程实战以及技巧
    Web学习篇之---html基础知识(一)
    μCOS-II系统之事件(event)的使用规则及Semaphore实例
    activiti自己定义流程之Spring整合activiti-modeler实例(一):环境搭建
    将ASP.NET用户控件转化为自定义控件
    【C#】Excel导出合并行和列并动态加载行与列
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4191275.html
Copyright © 2011-2022 走看看