JobSchedulerService 源码分析——Connec
2017-11-23 本文已影响0人
_夜
设置了网络约束条件的 Job 执行一次后不会被移除
一、调用流程
public JobSchedulerService(Context context) {
super(context);
// Create the controllers.
mControllers = new ArrayList<StateController>();
mControllers.add(ConnectivityController.get(this));
mControllers.add(TimeController.get(this));
mControllers.add(IdleController.get(this));
mControllers.add(BatteryController.get(this));
mHandler = new JobSchedulerService.JobHandler(context.getMainLooper());
mJobSchedulerStub = new JobSchedulerService.JobSchedulerStub();
mJobs = JobStore.initAndGet(this);
}
|
public static ConnectivityController get(JobSchedulerService jms) {
synchronized (sCreationLock) {
if (mSingleton == null) {
mSingleton = new ConnectivityController(jms, jms.getContext());
}
return mSingleton;
}
}
|
/**
* 注册广播,并获取当前的网络状态
*/
private ConnectivityController(StateChangedListener stateChangedListener, Context context) {
super(stateChangedListener, context);
// Register connectivity changed BR.
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiverAsUser(mConnectivityChangedReceiver, UserHandle.ALL, intentFilter, null, null);
ConnectivityService cs = (ConnectivityService) ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
if (cs != null) {
if (cs.getActiveNetworkInfo() != null) {
mNetworkConnected = cs.getActiveNetworkInfo().isConnected();
}
mNetworkUnmetered = mNetworkConnected && !cs.isActiveNetworkMetered();
}
}
二、添加需要追踪的 Job
@Override
public void maybeStartTrackingJob(JobStatus jobStatus) {
if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
synchronized (mTrackedJobs) {
jobStatus.connectivityConstraintSatisfied.set(mNetworkConnected);
jobStatus.unmeteredConstraintSatisfied.set(mNetworkUnmetered);
mTrackedJobs.add(jobStatus);
}
}
}
三、移除不再需要追踪的 Job
@Override
public void maybeStopTrackingJob(JobStatus jobStatus) {
if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
synchronized (mTrackedJobs) {
mTrackedJobs.remove(jobStatus);
}
}
}
四、ConnectivityController 驱动 Job 执行流程
1. 第一种驱动方式(似乎没被调用)
/**
* We know the network has just come up. We want to run any jobs that are ready.
* 该方法似乎不会被执行
*/
public synchronized void onNetworkActive() {
synchronized (mTrackedJobs) {
for (JobStatus js : mTrackedJobs) {
if (js.isReady()) {
// 所有的约束条件都已经满足,或者 deadlineConstraintSatisfied 已经满足
if (DEBUG) {
Slog.d(TAG, "Running " + js + " due to network activity.");
}
/**
* 触发 JobSchedulerService 把该 Job 加入 mPendingJobs,
* 并检查所有满足执行条件的 Job 放入 mPendingJobs,随后执行 mPendingJobs 中的 Job
*/
mStateChangedListener.onRunJobNow(js);
}
}
}
}
2. 第二种驱动方式
class ConnectivityChangedReceiver extends BroadcastReceiver {
/**
* We'll receive connectivity changes for each user here, which we process independently.
* We are only interested in the active network here. We're only interested in the active
* network, b/c the end result of this will be for apps to try to hit the network.
* @param context The Context in which the receiver is running.
* @param intent The Intent being received.
*/
// TODO: Test whether this will be called twice for each user.
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
final int networkType = intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE);
// Connectivity manager for THIS context - important!
final ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
final int userid = context.getUserId();
// This broadcast gets sent a lot, only update if the active network has changed.
if (activeNetwork == null) {
mNetworkUnmetered = false;
mNetworkConnected = false;
// 触发该 Controller 检查追踪列表中的 Job 状态是否发生变化
updateTrackedJobs(userid);
} else if (activeNetwork.getType() == networkType) { // 注意该条件的判断,可以参考这种写法
mNetworkUnmetered = false;
mNetworkConnected = !intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if (mNetworkConnected) { // No point making the call if we know there's no conn.
mNetworkUnmetered = !connManager.isActiveNetworkMetered();
}
// 触发该 Controller 检查追踪列表中的 Job 状态是否发生变化
updateTrackedJobs(userid);
}
}
}
};
触发该 Controller 检查追踪列表中的 Job 状态
/**
* 检查追踪列表中的 Job 状态是否发生变化
* 若有 Job 状态发生变化, 触发 JobSchedulerService 检测
* @param userId Id of the user for whom we are updating the connectivity state.
*/
private void updateTrackedJobs(int userId) {
synchronized (mTrackedJobs) {
boolean changed = false;
for (JobStatus js : mTrackedJobs) {
if (js.getUserId() != userId) {
continue;
}
boolean prevIsConnected = js.connectivityConstraintSatisfied.getAndSet(mNetworkConnected);
boolean prevIsMetered = js.unmeteredConstraintSatisfied.getAndSet(mNetworkUnmetered);
if (prevIsConnected != mNetworkConnected || prevIsMetered != mNetworkUnmetered) {
changed = true;
}
}
if (changed) {
/**
* 有 Job 状态发生变化, 触发 JobSchedulerService 检查所有满足执行条件的 Job,
* 根据策略决定是否放入 mPendingJobs,随后执行 mPendingJobs 中的 Job
*/
mStateChangedListener.onControllerStateChanged();
}
}
}