blob: de696b9e9bf5b5f446ae5cc595584029e33154e5 [file] [log] [blame]
package com.android.clockwork.healthservices;
import static com.android.clockwork.healthservices.HealthService.WHS_PACKAGE;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
/** An implementation of {@link HealthService.BindingAgent} that uses {@link Handler}. */
class HandlerBindingAgent extends Handler implements HealthService.BindingAgent {
private static final String TAG = "HandlerBindingAgent";
@VisibleForTesting static final int MSG_ATTEMPT_BIND = 0;
private static final String WHS_SERVICE_TO_BIND_TO =
WHS_PACKAGE + ".background.service.RecordingService";
/** The number of retries available to start with. */
@VisibleForTesting static final int FRESH_NUM_RETRIES = 20;
/**
* Number of attempts to be made without exponential retries. We will try to bind to WHS this
* number of times with constant intervals. For the reminder of the retries, each retry will
* be {@link EXPONENTIAL_MULTIPLIER} times later than the previous retry.
*/
private static final int NUM_NONEXPONENTIAL_RETRIES = 10;
private static final int EXPONENTIAL_MULTIPLIER = 2;
static final ComponentName WHS_SERVICE_COMPONENT_NAME =
new ComponentName(WHS_PACKAGE, WHS_SERVICE_TO_BIND_TO);
private final Context mContext;
private int mNumAttemptsLeft = FRESH_NUM_RETRIES;
private long mLastBindingDelayMillis = 0;
private ConnectionTracker mConnectionTracker;
HandlerBindingAgent(Context context) {
super(Looper.getMainLooper(), null, /* async= */ true);
mContext = context;
}
@Override // Handler
public void handleMessage(Message msg) {
Log.d(TAG, "Received a message: " + msg.what);
if (msg.what == MSG_ATTEMPT_BIND) {
try {
boolean bindingSuccess =
mContext.bindService(
new Intent().setComponent(WHS_SERVICE_COMPONENT_NAME),
mConnectionTracker,
Context.BIND_AUTO_CREATE | Context.BIND_ABOVE_CLIENT);
Log.d(TAG, "Binding success=" + bindingSuccess);
if (!bindingSuccess) {
if (--mNumAttemptsLeft > 0) {
int attemptsMadeBefore = FRESH_NUM_RETRIES - mNumAttemptsLeft;
boolean exponentialRetry = attemptsMadeBefore >= NUM_NONEXPONENTIAL_RETRIES;
long delay = mLastBindingDelayMillis * (exponentialRetry ? EXPONENTIAL_MULTIPLIER : 1);
Log.d(TAG,
"Binding failed: retrying after "
+ delay
+ "ms. Attempts left: "
+ mNumAttemptsLeft);
bind(delay);
} else {
Log.d(TAG, "Bidning failed: all attempts to bind failed.");
}
} else {
cancelPendingBinds();
mNumAttemptsLeft = FRESH_NUM_RETRIES;
}
} catch (SecurityException e) {
Log.e(TAG, "Error attempting binding to WHS.", e);
}
}
}
@Override // BindingAgent
public void bind(long delayMillis) {
cancelPendingBinds();
mLastBindingDelayMillis = delayMillis;
sendEmptyMessageDelayed(MSG_ATTEMPT_BIND, delayMillis);
}
@Override // BindingAgent
public void cancelPendingBinds() {
Log.d(TAG, "Cancelling pending binds");
removeMessages(MSG_ATTEMPT_BIND);
}
void setConnectionTracker(ConnectionTracker connectionTracker) {
mConnectionTracker = connectionTracker;
}
}