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账号与同步之发起同步,布布扣,bubuko.com

时间: 2024-10-07 22:01:10

android账号与同步之发起同步的相关文章

android账号与同步之同步实现

上一篇博文我先介绍了账号与同步的账号管理,这篇就介绍一下还有一部分.就是android给提供的sync同步机制的使用. 事实上sync机制的使用和上一篇博文中介绍的账号管理非常类似,也是基于binder机制的跨进程通信.首先它须要一个Service.这个服务提供一个Action给系统以便系统能找到它.然后就是继承和实现AbstractThreadedSyncAdapter.此类中包括实现了ISyncAdapter.Stub内部类.这个内部类封装了远程接口调用,这个类getSyncAdapterB

android账号与同步之账号管理

在android提供的sdk中,samples目录下有一个叫SampleSyncAdapter的示例,它是一个账号与同步的实例,比如Google原始的android手机可以使用Google账号进行数据的同步.具体 的比如你想实时同步你的通讯录到服务端,这时候你就可以通过这个实例来了解android提供的同步机制,从而实现自己的同步功能. 本片博文先介绍一下账号的管理部分.至于账号管理的代码主要是在authenticator包下的三个类里面,还有就是一个叫authenticator的xml文件.

一步一步教你在 Android 里创建自己的账号系统(二)--同步数据以及设计账号页面

大家如果喜欢我的博客,请关注一下我的微博,请点击这里(http://weibo.com/kifile),谢谢 转载请标明出处(http://blog.csdn.net/kifile),再次感谢 在前一篇文章中(一步一步教你在 Android 里创建自己的账号系统(一)),我向大家介绍了如何在 Android 系统中创建自己的账户系统,接下来我会向大家详细介绍一下如何使用账户系统. (一)同步数据 通常而言,我们会在两种情况下使用我们的账号系统: (1)登陆验证 登陆验证其实是一个很实用的功能,试

Android 建立手机与手表数据同步机制总结

Android Wear 数据同步机制总结 当手机与手表建立蓝牙连接之后,数据就可以通过Google Play Service进行传输. 同步数据对象Data Item DataItem提供手机与手表数据存储的自动同步,一个DataItem对象由其创建者与路径组成的URI所确定.一个DataItem对象为手机和手表提供了一个数据通路,开发者通过改变指定的DataItem实现手机和手表的数据自动同步. 访问数据层API DataItem可以提供手机和手表数据的保存,改变该对象的操作则依赖数据层AP

rsync远程同步(定期同步、实时同步)

关于rsync . 一款快速增量备份工具 1.Remote Sync,远程同步 2.支持本地复制,或者与其他SSH.rsync主机同步 3.官方网站: http://rsync.samba.org 配置rsync源服务器 rsync同步源: 指备份操作的远程服务器,也称为备份源 配置rsync源 基本思路: 1.建立rsyncd.conf配置文件.独立的账号文件 .启用rsync的--daemon模式 应用示例: 1.户backuper,允许下行同步 2.操作的目录为/var/www/html/

Tibco RV request/reply 的同步與非同步

Tibco RV 有提供 request/reply 模式,也有提供 publish/subscribe 模式,這兩種模式的用途分別是,request/reply 用在一對一的狀況下,而 publish/subscribe 則是用在一對多.雖然 request/reply 是用在一對一,Tibco RV 仍提供了同步與非同步兩種模式,在說明同步和非同步之前,先看一下 server 端的程式,如下: 1 package idv.steven.rv; 2 3 import com.tibco.tib

真正的inotify+rsync实时同步 彻底告别同步慢

我们公司在用inotify+rsync做实时同步,来解决分布式集群文件一致性的问题.但当web文件越来越多(百万级数量html,jpg等小 文件),同步就越来越慢,根本做不到实时,按照网上的调优方法都尝试过,问题根本没有解决.经过我一翻细致研究,终于把慢的核心问题研究明白,先总结一句 inotifywait响应不会有延迟,rsync也很快.大家同样有慢的烦恼,那是因为网上的inotify+rsync的教程都是坑.下面我们来分 析. inotifywait 单独分析 /usr/local/bin/

JAVA之旅(十三)——线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this

JAVA之旅(十三)--线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this 我们继续上个篇幅接着讲线程的知识点 一.线程的安全性 当我们开启四个窗口(线程)把票陆陆续续的卖完了之后,我们要反思一下,这里面有没有安全隐患呢?在实际情况中,这种事情我们是必须要去考虑安全问题的,那我们模拟一下错误 package com.lgl.hellojava; import javax.security.auth.callback.TextInputCallback

inotify+rsync实时同步 彻底告别同步慢

#!/bin/bash src=/data/            # 需要同步的源路径 des=data              # 目标服务器上 rsync --daemon 发布的名称,rsync --daemon这里就不做介绍了,网上搜一下,比较简单. rsync_passwd_file=/etc/rsyncd.passwd            # rsync验证的密码文件 ip1=192.168.0.18      # 目标服务器1 ip2=192.168.0.19      #