1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/* 2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project 3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License"); 5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License. 6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at 7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * http://www.apache.org/licenses/LICENSE-2.0 9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software 11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS, 12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and 14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License. 15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.datamodel.action; 18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.app.AlarmManager; 20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.app.IntentService; 21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.app.PendingIntent; 22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.BroadcastReceiver; 23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context; 24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Intent; 25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Bundle; 26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.SystemClock; 27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.Factory; 29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.DataModel; 30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.LogUtil; 31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.LoggingTimer; 32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.WakeLockHelper; 33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.google.common.annotations.VisibleForTesting; 34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/** 36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * ActionService used to perform background processing for data model 37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class ActionServiceImpl extends IntentService { 39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG; 40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static final boolean VERBOSE = false; 41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public ActionServiceImpl() { 43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd super("ActionService"); 44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Start action by sending intent to the service 48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param action - action to start 49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static void startAction(final Action action) { 51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Intent intent = makeIntent(OP_START_ACTION); 52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Bundle actionBundle = new Bundle(); 53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd actionBundle.putParcelable(BUNDLE_ACTION, action); 54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd intent.putExtra(EXTRA_ACTION_BUNDLE, actionBundle); 55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd action.markStart(); 56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd startServiceWithIntent(intent); 57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Schedule an action to run after specified delay using alarm manager to send pendingintent 61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param action - action to start 62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param requestCode - request code used to collapse requests 63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param delayMs - delay in ms (from now) before action will start 64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static void scheduleAction(final Action action, final int requestCode, 66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final long delayMs) { 67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Intent intent = PendingActionReceiver.makeIntent(OP_START_ACTION); 68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Bundle actionBundle = new Bundle(); 69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd actionBundle.putParcelable(BUNDLE_ACTION, action); 70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd intent.putExtra(EXTRA_ACTION_BUNDLE, actionBundle); 71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd PendingActionReceiver.scheduleAlarm(intent, requestCode, delayMs); 73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Handle response returned by BackgroundWorker 77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param request - request generating response 78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param response - response from service 79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static void handleResponseFromBackgroundWorker(final Action action, 81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Bundle response) { 82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Intent intent = makeIntent(OP_RECEIVE_BACKGROUND_RESPONSE); 83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Bundle actionBundle = new Bundle(); 85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd actionBundle.putParcelable(BUNDLE_ACTION, action); 86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd intent.putExtra(EXTRA_ACTION_BUNDLE, actionBundle); 87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd intent.putExtra(EXTRA_WORKER_RESPONSE, response); 88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd startServiceWithIntent(intent); 90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Handle response returned by BackgroundWorker 94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param request - request generating failure 95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static void handleFailureFromBackgroundWorker(final Action action, 97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Exception exception) { 98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Intent intent = makeIntent(OP_RECEIVE_BACKGROUND_FAILURE); 99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Bundle actionBundle = new Bundle(); 101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd actionBundle.putParcelable(BUNDLE_ACTION, action); 102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd intent.putExtra(EXTRA_ACTION_BUNDLE, actionBundle); 103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd intent.putExtra(EXTRA_WORKER_EXCEPTION, exception); 104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd startServiceWithIntent(intent); 106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // ops 109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @VisibleForTesting 110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final int OP_START_ACTION = 200; 111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @VisibleForTesting 112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final int OP_RECEIVE_BACKGROUND_RESPONSE = 201; 113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @VisibleForTesting 114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final int OP_RECEIVE_BACKGROUND_FAILURE = 202; 115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // extras 117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @VisibleForTesting 118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final String EXTRA_OP_CODE = "op"; 119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @VisibleForTesting 120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final String EXTRA_ACTION_BUNDLE = "datamodel_action_bundle"; 121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @VisibleForTesting 122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final String EXTRA_WORKER_EXCEPTION = "worker_exception"; 123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @VisibleForTesting 124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final String EXTRA_WORKER_RESPONSE = "worker_response"; 125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @VisibleForTesting 126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final String EXTRA_WORKER_UPDATE = "worker_update"; 127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @VisibleForTesting 128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final String BUNDLE_ACTION = "bundle_action"; 129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private BackgroundWorker mBackgroundWorker; 131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Allocate an intent with a specific opcode. 134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static Intent makeIntent(final int opcode) { 136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Intent intent = new Intent(Factory.get().getApplicationContext(), 137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd ActionServiceImpl.class); 138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd intent.putExtra(EXTRA_OP_CODE, opcode); 139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return intent; 140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Broadcast receiver for alarms scheduled through ActionService. 144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static class PendingActionReceiver extends BroadcastReceiver { 146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd static final String ACTION = "com.android.messaging.datamodel.PENDING_ACTION"; 147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Allocate an intent with a specific opcode and alarm action. 150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static Intent makeIntent(final int opcode) { 152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Intent intent = new Intent(Factory.get().getApplicationContext(), 153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd PendingActionReceiver.class); 154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd intent.setAction(ACTION); 155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd intent.putExtra(EXTRA_OP_CODE, opcode); 156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return intent; 157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static void scheduleAlarm(final Intent intent, final int requestCode, 160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final long delayMs) { 161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Context context = Factory.get().getApplicationContext(); 162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final PendingIntent pendingIntent = PendingIntent.getBroadcast( 163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd context, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT); 164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final AlarmManager mgr = 166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (delayMs < Long.MAX_VALUE) { 169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd SystemClock.elapsedRealtime() + delayMs, pendingIntent); 171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } else { 172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mgr.cancel(pendingIntent); 173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * {@inheritDoc} 178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void onReceive(final Context context, final Intent intent) { 181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd ActionServiceImpl.startServiceWithIntent(intent); 182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Creates a pending intent that will trigger a data model action when the intent is 187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * triggered 188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static PendingIntent makeStartActionPendingIntent(final Context context, 190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Action action, final int requestCode, final boolean launchesAnActivity) { 191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Intent intent = PendingActionReceiver.makeIntent(OP_START_ACTION); 192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Bundle actionBundle = new Bundle(); 193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd actionBundle.putParcelable(BUNDLE_ACTION, action); 194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd intent.putExtra(EXTRA_ACTION_BUNDLE, actionBundle); 195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (launchesAnActivity) { 196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return PendingIntent.getBroadcast(context, requestCode, intent, 199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd PendingIntent.FLAG_UPDATE_CURRENT); 200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * {@inheritDoc} 204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void onCreate() { 207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd super.onCreate(); 208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mBackgroundWorker = DataModel.get().getBackgroundWorkerForActionService(); 209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd DataModel.get().getConnectivityUtil().registerForSignalStrength(); 210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void onDestroy() { 214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd super.onDestroy(); 215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd DataModel.get().getConnectivityUtil().unregisterForSignalStrength(); 216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static final String WAKELOCK_ID = "bugle_datamodel_service_wakelock"; 219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @VisibleForTesting 220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd static WakeLockHelper sWakeLock = new WakeLockHelper(WAKELOCK_ID); 221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Queue intent to the ActionService after acquiring wake lock 224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static void startServiceWithIntent(final Intent intent) { 226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Context context = Factory.get().getApplicationContext(); 227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final int opcode = intent.getIntExtra(EXTRA_OP_CODE, 0); 228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Increase refCount on wake lock - acquiring if necessary 229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (VERBOSE) { 230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.v(TAG, "acquiring wakelock for opcode " + opcode); 231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sWakeLock.acquire(context, intent, opcode); 233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd intent.setClass(context, ActionServiceImpl.class); 234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // TODO: Note that intent will be quietly discarded if it exceeds available rpc 236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // memory (in total around 1MB). See this article for background 237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // http://developer.android.com/reference/android/os/TransactionTooLargeException.html 238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Perhaps we should keep large structures in the action monitor? 239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (context.startService(intent) == null) { 240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.e(TAG, 241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd "ActionService.startServiceWithIntent: failed to start service for intent " 242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd + intent); 243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sWakeLock.release(intent, opcode); 244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * {@inheritDoc} 249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected void onHandleIntent(final Intent intent) { 252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (intent == null) { 253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Shouldn't happen but sometimes does following another crash. 254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.w(TAG, "ActionService.onHandleIntent: Called with null intent"); 255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return; 256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final int opcode = intent.getIntExtra(EXTRA_OP_CODE, 0); 258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sWakeLock.ensure(intent, opcode); 259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Action action; 262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Bundle actionBundle = intent.getBundleExtra(EXTRA_ACTION_BUNDLE); 263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd actionBundle.setClassLoader(getClassLoader()); 264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd switch(opcode) { 265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd case OP_START_ACTION: { 266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd action = (Action) actionBundle.getParcelable(BUNDLE_ACTION); 267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd executeAction(action); 268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd break; 269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd case OP_RECEIVE_BACKGROUND_RESPONSE: { 272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd action = (Action) actionBundle.getParcelable(BUNDLE_ACTION); 273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Bundle response = intent.getBundleExtra(EXTRA_WORKER_RESPONSE); 274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd processBackgroundResponse(action, response); 275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd break; 276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 277d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 278d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd case OP_RECEIVE_BACKGROUND_FAILURE: { 279d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd action = (Action) actionBundle.getParcelable(BUNDLE_ACTION); 280d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd processBackgroundFailure(action); 281d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd break; 282d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 283d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 284d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd default: 285d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd throw new RuntimeException("Unrecognized opcode in ActionServiceImpl"); 286d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 287d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 288d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd action.sendBackgroundActions(mBackgroundWorker); 289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } finally { 290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Decrease refCount on wake lock - releasing if necessary 291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sWakeLock.release(intent, opcode); 292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static final long EXECUTION_TIME_WARN_LIMIT_MS = 1000; // 1 second 296d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 297d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Local execution of action on ActionService thread 298d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 299d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private void executeAction(final Action action) { 300d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd action.markBeginExecute(); 301d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 302d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final LoggingTimer timer = createLoggingTimer(action, "#executeAction"); 303d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd timer.start(); 304d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 305d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Object result = action.executeAction(); 306d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 307d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd timer.stopAndLog(); 308d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 309d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd action.markEndExecute(result); 310d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 311d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 312d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 313d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Process response on ActionService thread 314d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 315d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private void processBackgroundResponse(final Action action, final Bundle response) { 316d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final LoggingTimer timer = createLoggingTimer(action, "#processBackgroundResponse"); 317d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd timer.start(); 318d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 319d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd action.processBackgroundWorkResponse(response); 320d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 321d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd timer.stopAndLog(); 322d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 323d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 324d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 325d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Process failure on ActionService thread 326d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 327d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private void processBackgroundFailure(final Action action) { 328d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final LoggingTimer timer = createLoggingTimer(action, "#processBackgroundFailure"); 329d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd timer.start(); 330d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 331d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd action.processBackgroundWorkFailure(); 332d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 333d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd timer.stopAndLog(); 334d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 335d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 336d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static LoggingTimer createLoggingTimer( 337d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Action action, final String methodName) { 338d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return new LoggingTimer(TAG, action.getClass().getSimpleName() + methodName, 339d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd EXECUTION_TIME_WARN_LIMIT_MS); 340d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 341d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd} 342