diff options
author | Christopher Tate <ctate@google.com> | 2014-06-16 15:51:39 -0700 |
---|---|---|
committer | Christopher Tate <ctate@google.com> | 2014-06-17 12:14:45 -0700 |
commit | cf1a2f73fc102be2ac7060ac97d4682bb2565ca5 (patch) | |
tree | f00e01d283dbf43199d2d3692d578b7e18e9326c | |
parent | 6b2df21ecacfa6826a85cabdf8d6fe0e81fe11d9 (diff) | |
download | frameworks_base-cf1a2f73fc102be2ac7060ac97d4682bb2565ca5.zip frameworks_base-cf1a2f73fc102be2ac7060ac97d4682bb2565ca5.tar.gz frameworks_base-cf1a2f73fc102be2ac7060ac97d4682bb2565ca5.tar.bz2 |
Switch everything to scheduled jobs
Everything that used the IdleMaintenance APIs/broadcasts gets to use the
spiffy new JobScheduler instead. Hooray!
On top of that, the now-obsolete "idle maintenance" APIs are now gone
entirely. Double hooray!
Bug 14993295
Change-Id: I5fb67c296ca8cd0ba8a2c8760a0f0d9d962d813b
16 files changed, 54 insertions, 1434 deletions
@@ -94,8 +94,6 @@ LOCAL_SRC_FILES += \ core/java/android/app/backup/IFullBackupRestoreObserver.aidl \ core/java/android/app/backup/IRestoreObserver.aidl \ core/java/android/app/backup/IRestoreSession.aidl \ - core/java/android/app/maintenance/IIdleCallback.aidl \ - core/java/android/app/maintenance/IIdleService.aidl \ core/java/android/bluetooth/IBluetooth.aidl \ core/java/android/bluetooth/IBluetoothA2dp.aidl \ core/java/android/bluetooth/IBluetoothA2dpSink.aidl \ diff --git a/CleanSpec.mk b/CleanSpec.mk index 5d92792..1968a78 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -34,9 +34,9 @@ # made today requires touching the same file, just copy the old # touch step and add it to the end of the list. # -# ************************************************ -# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST -# ************************************************ +# ***************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER +# ***************************************************************** # For example: #$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) @@ -194,10 +194,15 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framew $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/app/wearable) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/tv/ITv*) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates) - -# ************************************************ -# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST -# ************************************************ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/classes/android/app/task) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app/task) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/classes/android/app/TaskManager) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app/maintenance) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/classes/android/app/maintenance) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes/android/app/maintenance) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/classes/android/app/maintenance) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/app/maintenance) + +# ****************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER +# ****************************************************************** diff --git a/core/java/android/app/maintenance/IIdleCallback.aidl b/core/java/android/app/maintenance/IIdleCallback.aidl deleted file mode 100644 index 582dede..0000000 --- a/core/java/android/app/maintenance/IIdleCallback.aidl +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright 2014, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.maintenance; - -import android.app.maintenance.IIdleService; - -/** - * The server side of the idle maintenance IPC protocols. The app-side implementation - * invokes on this interface to indicate completion of the (asynchronous) instructions - * issued by the server. - * - * In all cases, the 'who' parameter is the caller's service binder, used to track - * which idle service instance is reporting. - * - * {@hide} - */ -interface IIdleCallback { - /** - * Acknowledge receipt and processing of the asynchronous "start idle work" incall. - * 'result' is true if the app wants some time to perform ongoing background - * idle-time work; or false if the app declares that it does not need any time - * for such work. - */ - void acknowledgeStart(int token, boolean result); - - /** - * Acknowledge receipt and processing of the asynchronous "stop idle work" incall. - */ - void acknowledgeStop(int token); - - /* - * Tell the idle service manager that we're done with our idle maintenance, so that - * it can go on to the next one and stop attributing wakelock time to us etc. - * - * @param opToken The identifier passed in the startIdleMaintenance() call that - * indicated the beginning of this service's idle timeslice. - */ - void idleFinished(int token); -} diff --git a/core/java/android/app/maintenance/IIdleService.aidl b/core/java/android/app/maintenance/IIdleService.aidl deleted file mode 100644 index 54abccd..0000000 --- a/core/java/android/app/maintenance/IIdleService.aidl +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright 2014, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.maintenance; - -import android.app.maintenance.IIdleCallback; - -/** - * Interface that the framework uses to communicate with application code - * that implements an idle-time "maintenance" service. End user code does - * not implement this interface directly; instead, the app's idle service - * implementation will extend android.app.maintenance.IdleService. - * {@hide} - */ -oneway interface IIdleService { - /** - * Begin your idle-time work. - */ - void startIdleMaintenance(IIdleCallback callbackBinder, int token); - void stopIdleMaintenance(IIdleCallback callbackBinder, int token); -} diff --git a/core/java/android/app/maintenance/IdleService.java b/core/java/android/app/maintenance/IdleService.java deleted file mode 100644 index 2331b81..0000000 --- a/core/java/android/app/maintenance/IdleService.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.maintenance; - -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.app.Service; -import android.content.Intent; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.RemoteException; -import android.util.Log; -import android.util.Slog; - -/** - * Idle maintenance API. Full docs TBW (to be written). - */ -public abstract class IdleService extends Service { - private static final String TAG = "IdleService"; - - static final int MSG_START = 1; - static final int MSG_STOP = 2; - static final int MSG_FINISH = 3; - - IdleHandler mHandler; - IIdleCallback mCallbackBinder; - int mToken; - final Object mHandlerLock = new Object(); - - void ensureHandler() { - synchronized (mHandlerLock) { - if (mHandler == null) { - mHandler = new IdleHandler(getMainLooper()); - } - } - } - - /** - * TBW: the idle service should supply an intent-filter handling this intent - * <p> - * <p class="note">The application must also protect the idle service with the - * {@code "android.permission.BIND_IDLE_SERVICE"} permission to ensure that other - * applications cannot maliciously bind to it. If an idle service's manifest - * declaration does not require that permission, it will never be invoked. - * </p> - */ - @SdkConstant(SdkConstantType.SERVICE_ACTION) - public static final String SERVICE_INTERFACE = - "android.service.idle.IdleService"; - - /** - * Idle services must be protected with this permission: - * - * <pre class="prettyprint"> - * <service android:name="MyIdleService" - * android:permission="android.permission.BIND_IDLE_SERVICE" > - * ... - * </service> - * </pre> - * - * <p>If an idle service is declared in the manifest but not protected with this - * permission, that service will be ignored by the OS. - */ - public static final String PERMISSION_BIND = - "android.permission.BIND_IDLE_SERVICE"; - - // Trampoline: the callbacks are always run on the main thread - IIdleService mBinder = new IIdleService.Stub() { - @Override - public void startIdleMaintenance(IIdleCallback callbackBinder, int token) - throws RemoteException { - ensureHandler(); - Message msg = mHandler.obtainMessage(MSG_START, token, 0, callbackBinder); - mHandler.sendMessage(msg); - } - - @Override - public void stopIdleMaintenance(IIdleCallback callbackBinder, int token) - throws RemoteException { - ensureHandler(); - Message msg = mHandler.obtainMessage(MSG_STOP, token, 0, callbackBinder); - mHandler.sendMessage(msg); - } - }; - - /** - * Your application may begin doing "idle" maintenance work in the background. - * <p> - * Your application may continue to run in the background until it receives a call - * to {@link #onIdleStop()}, at which point you <i>must</i> cease doing work. The - * OS will hold a wakelock on your application's behalf from the time this method is - * called until after the following call to {@link #onIdleStop()} returns. - * </p> - * <p> - * Returning {@code false} from this method indicates that you have no ongoing work - * to do at present. The OS will respond by immediately calling {@link #onIdleStop()} - * and returning your application to its normal stopped state. Returning {@code true} - * indicates that the application is indeed performing ongoing work, so the OS will - * let your application run in this state until it's no longer appropriate. - * </p> - * <p> - * You will always receive a matching call to {@link #onIdleStop()} even if your - * application returns {@code false} from this method. - * - * @return {@code true} to indicate that the application wishes to perform some ongoing - * background work; {@code false} to indicate that it does not need to perform such - * work at present. - */ - public abstract boolean onIdleStart(); - - /** - * Your app's maintenance opportunity is over. Once the application returns from - * this method, the wakelock held by the OS on its behalf will be released. - */ - public abstract void onIdleStop(); - - /** - * Tell the OS that you have finished your idle work. Calling this more than once, - * or calling it when you have not received an {@link #onIdleStart()} callback, is - * an error. - * - * <p>It is safe to call {@link #finishIdle()} from any thread. - */ - public final void finishIdle() { - ensureHandler(); - mHandler.sendEmptyMessage(MSG_FINISH); - } - - class IdleHandler extends Handler { - IdleHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_START: { - // Call the concrete onIdleStart(), reporting its return value back to - // the OS. If onIdleStart() throws, report it as a 'false' return but - // rethrow the exception at the offending app. - boolean result = false; - IIdleCallback callbackBinder = (IIdleCallback) msg.obj; - mCallbackBinder = callbackBinder; - final int token = mToken = msg.arg1; - try { - result = IdleService.this.onIdleStart(); - } catch (Exception e) { - Log.e(TAG, "Unable to start idle workload", e); - throw new RuntimeException(e); - } finally { - // don't bother if the service already called finishIdle() - if (mCallbackBinder != null) { - try { - callbackBinder.acknowledgeStart(token, result); - } catch (RemoteException re) { - Log.e(TAG, "System unreachable to start idle workload"); - } - } - } - break; - } - - case MSG_STOP: { - // Structured just like MSG_START for the stop-idle bookend call. - IIdleCallback callbackBinder = (IIdleCallback) msg.obj; - final int token = msg.arg1; - try { - IdleService.this.onIdleStop(); - } catch (Exception e) { - Log.e(TAG, "Unable to stop idle workload", e); - throw new RuntimeException(e); - } finally { - if (mCallbackBinder != null) { - try { - callbackBinder.acknowledgeStop(token); - } catch (RemoteException re) { - Log.e(TAG, "System unreachable to stop idle workload"); - } - } - } - break; - } - - case MSG_FINISH: { - if (mCallbackBinder != null) { - try { - mCallbackBinder.idleFinished(mToken); - } catch (RemoteException e) { - Log.e(TAG, "System unreachable to finish idling"); - } finally { - mCallbackBinder = null; - } - } else { - Log.e(TAG, "finishIdle() called but the idle service is not started"); - } - break; - } - - default: { - Slog.w(TAG, "Unknown message " + msg.what); - } - } - } - } - - /** @hide */ - @Override - public final IBinder onBind(Intent intent) { - return mBinder.asBinder(); - } - -} diff --git a/core/java/android/app/maintenance/package.html b/core/java/android/app/maintenance/package.html deleted file mode 100644 index 1c9bf9d..0000000 --- a/core/java/android/app/maintenance/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<html> -<body> - {@hide} -</body> -</html> diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index edca101..c08c5e2 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2928,6 +2928,12 @@ android:permission="android.permission.BIND_JOB_SERVICE" > </service> + <service + android:name="com.android.server.pm.BackgroundDexOptService" + android:exported="true" + android:permission="android.permission.BIND_JOB_SERVICE"> + </service> + </application> </manifest> diff --git a/services/core/java/com/android/server/IdleMaintenanceService.java b/services/core/java/com/android/server/IdleMaintenanceService.java deleted file mode 100644 index acc6abe..0000000 --- a/services/core/java/com/android/server/IdleMaintenanceService.java +++ /dev/null @@ -1,818 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.app.maintenance.IIdleCallback; -import android.app.maintenance.IIdleService; -import android.app.maintenance.IdleService; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.ServiceConnection; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.os.Handler; -import android.os.PowerManager; -import android.os.PowerManager.WakeLock; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.Process; -import android.os.RemoteException; -import android.os.SystemClock; -import android.os.UserHandle; -import android.os.WorkSource; -import android.util.ArrayMap; -import android.util.Log; -import android.util.Slog; -import android.util.SparseArray; - -import java.util.LinkedList; -import java.util.List; -import java.util.Random; - -/** - * This service observes the device state and when applicable sends - * broadcasts at the beginning and at the end of a period during which - * observers can perform idle maintenance tasks. Typical use of the - * idle maintenance is to perform somehow expensive tasks that can be - * postponed to a moment when they will not degrade user experience. - * - * The current implementation is very simple. The start of a maintenance - * window is announced if: the screen is off or showing a dream AND the - * battery level is more than twenty percent AND at least one hour passed - * activity). - * - * The end of a maintenance window is announced only if: a start was - * announced AND the screen turned on or a dream was stopped. - * - * Method naming note: - * Methods whose name ends with "Tm" must only be called from the main thread. - */ -public class IdleMaintenanceService extends BroadcastReceiver { - - private static final boolean DEBUG = false; - - private static final String TAG = IdleMaintenanceService.class.getSimpleName(); - - private static final int LAST_USER_ACTIVITY_TIME_INVALID = -1; - - private static final long MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS = 24 * 60 * 60 * 1000; // 1 day - - private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING = 30; // percent - - private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING = 80; // percent - - private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING = 20; // percent - - private static final long MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START = 71 * 60 * 1000; // 71 min - - private static final long MAX_IDLE_MAINTENANCE_DURATION = 71 * 60 * 1000; // 71 min - - private static final String ACTION_UPDATE_IDLE_MAINTENANCE_STATE = - "com.android.server.IdleMaintenanceService.action.UPDATE_IDLE_MAINTENANCE_STATE"; - - private static final String ACTION_FORCE_IDLE_MAINTENANCE = - "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE"; - - static final int MSG_OP_COMPLETE = 1; - static final int MSG_IDLE_FINISHED = 2; - static final int MSG_TIMEOUT = 3; - - // when a timeout happened, what were we expecting? - static final int VERB_BINDING = 1; - static final int VERB_IDLING = 2; - static final int VERB_ENDING = 3; - - // What are our relevant timeouts / allocated slices? - static final long OP_TIMEOUT = 8 * 1000; // 8 seconds to bind or ack the start - static final long IDLE_TIMESLICE = 10 * 60 * 1000; // ten minutes for each idler - - private final AlarmManager mAlarmService; - private final BatteryService mBatteryService; - private final PendingIntent mUpdateIdleMaintenanceStatePendingIntent; - private final Context mContext; - private final WakeLock mWakeLock; - private final WorkSource mSystemWorkSource = new WorkSource(Process.myUid()); - - private long mLastIdleMaintenanceStartTimeMillis; - private long mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID; - private boolean mIdleMaintenanceStarted; - - final IdleCallback mCallback; - final Handler mHandler; - - final Random mTokenGenerator = new Random(); - - int makeToken() { - int token; - do { - token = mTokenGenerator.nextInt(Integer.MAX_VALUE); - } while (token == 0); - return token; - } - - class ActiveTask { - public IdleServiceInfo who; - public int verb; - public int token; - - ActiveTask(IdleServiceInfo target, int action) { - who = target; - verb = action; - token = makeToken(); - } - - @Override - public String toString() { - return "ActiveTask{" + Integer.toHexString(this.hashCode()) - + " : verb=" + verb - + " : token=" + token - + " : "+ who + "}"; - } - } - - // What operations are in flight? - final SparseArray<ActiveTask> mPendingOperations = new SparseArray<ActiveTask>(); - - // Idle service queue management - class IdleServiceInfo { - public final ComponentName componentName; - public final int uid; - public IIdleService service; - - IdleServiceInfo(ResolveInfo info, ComponentName cname) { - componentName = cname; // derived from 'info' but this avoids an extra object - uid = info.serviceInfo.applicationInfo.uid; - service = null; - } - - @Override - public int hashCode() { - return componentName.hashCode(); - } - - @Override - public String toString() { - return "IdleServiceInfo{" + componentName - + " / " + (service == null ? "null" : service.asBinder()) + "}"; - } - } - - final ArrayMap<ComponentName, IdleServiceInfo> mIdleServices = - new ArrayMap<ComponentName, IdleServiceInfo>(); - final LinkedList<IdleServiceInfo> mIdleServiceQueue = new LinkedList<IdleServiceInfo>(); - IdleServiceInfo mCurrentIdler; // set when we've committed to launching an idler - IdleServiceInfo mLastIdler; // end of queue when idling begins - - void reportNoTimeout(int token, boolean result) { - final Message msg = mHandler.obtainMessage(MSG_OP_COMPLETE, result ? 1 : 0, token); - mHandler.sendMessage(msg); - } - - // Binder acknowledgment trampoline - class IdleCallback extends IIdleCallback.Stub { - @Override - public void acknowledgeStart(int token, boolean result) throws RemoteException { - reportNoTimeout(token, result); - } - - @Override - public void acknowledgeStop(int token) throws RemoteException { - reportNoTimeout(token, false); - } - - @Override - public void idleFinished(int token) throws RemoteException { - if (DEBUG) { - Slog.v(TAG, "idleFinished: " + token); - } - final Message msg = mHandler.obtainMessage(MSG_IDLE_FINISHED, 0, token); - mHandler.sendMessage(msg); - } - } - - // Stuff that we run on a Handler - class IdleHandler extends Handler { - public IdleHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - final int token = msg.arg2; - - switch (msg.what) { - case MSG_OP_COMPLETE: { - if (DEBUG) { - Slog.i(TAG, "MSG_OP_COMPLETE of " + token); - } - ActiveTask task = mPendingOperations.get(token); - if (task != null) { - mPendingOperations.remove(token); - removeMessages(MSG_TIMEOUT); - - handleOpCompleteTm(task, msg.arg1); - } else { - // Can happen in a race between timeout and actual - // (belated) completion of a "begin idling" or similar - // operation. In that state we've already processed the - // timeout, so we intentionally no-op here. - if (DEBUG) { - Slog.w(TAG, "Belated op-complete of " + token); - } - } - break; - } - - case MSG_IDLE_FINISHED: { - if (DEBUG) { - Slog.i(TAG, "MSG_IDLE_FINISHED of " + token); - } - ActiveTask task = mPendingOperations.get(token); - if (task != null) { - if (DEBUG) { - Slog.i(TAG, "... removing task " + token); - } - mPendingOperations.remove(token); - removeMessages(MSG_TIMEOUT); - - handleIdleFinishedTm(task); - } else { - // Can happen "legitimately" from an app explicitly calling - // idleFinished() after already having been told that its slice - // has ended. - if (DEBUG) { - Slog.w(TAG, "Belated idle-finished of " + token); - } - } - break; - } - - case MSG_TIMEOUT: { - if (DEBUG) { - Slog.i(TAG, "MSG_TIMEOUT of " + token); - } - ActiveTask task = mPendingOperations.get(token); - if (task != null) { - mPendingOperations.remove(token); - removeMessages(MSG_OP_COMPLETE); - - handleTimeoutTm(task); - } else { - // This one should not happen; we flushed timeout messages - // whenever we entered a state after which we have established - // that they are not appropriate. - Slog.w(TAG, "Unexpected timeout of " + token); - } - break; - } - - default: - Slog.w(TAG, "Unknown message: " + msg.what); - } - } - } - - void handleTimeoutTm(ActiveTask task) { - switch (task.verb) { - case VERB_BINDING: { - // We were trying to bind to this service, but it wedged or otherwise - // failed to respond in time. Let it stay in the queue for the next - // time around, but just give up on it for now and go on to the next. - startNextIdleServiceTm(); - break; - } - case VERB_IDLING: { - // The service has reached the end of its designated idle timeslice. - // This is not considered an error. - if (DEBUG) { - Slog.i(TAG, "Idler reached end of timeslice: " + task.who); - } - sendEndIdleTm(task.who); - break; - } - case VERB_ENDING: { - if (mCurrentIdler == task.who) { - if (DEBUG) { - Slog.i(TAG, "Task timed out when ending; unbind needed"); - } - handleIdleFinishedTm(task); - } else { - if (DEBUG) { - Slog.w(TAG, "Ending timeout for non-current idle service!"); - } - } - break; - } - default: { - Slog.w(TAG, "Unknown timeout state " + task.verb); - break; - } - } - } - - void handleOpCompleteTm(ActiveTask task, int result) { - if (DEBUG) { - Slog.i(TAG, "handleOpComplete : task=" + task + " result=" + result); - } - if (task.verb == VERB_IDLING) { - // If the service was told to begin idling and responded positively, then - // it has begun idling and will eventually either explicitly finish, or - // reach the end of its allotted timeslice. It's running free now, so we - // just schedule the idle-expiration timeout under the token it's already been - // given and let it keep going. - if (result != 0) { - scheduleOpTimeoutTm(task); - } else { - // The idle service has indicated that it does not, in fact, - // need to run at present, so we immediately indicate that it's - // to finish idling, and go on to the next idler. - if (DEBUG) { - Slog.i(TAG, "Idler declined idling; moving along"); - } - sendEndIdleTm(task.who); - } - } else { - // In the idling case, the task will be cleared either as the result of a timeout - // or of an explicit idleFinished(). For all other operations (binding, ending) we - // are done with the task as such, so we remove it from our bookkeeping. - if (DEBUG) { - Slog.i(TAG, "Clearing task " + task); - } - mPendingOperations.remove(task.token); - if (task.verb == VERB_ENDING) { - // The last bit of handshaking around idle cessation for this target - handleIdleFinishedTm(task); - } - } - } - - void handleIdleFinishedTm(ActiveTask task) { - final IdleServiceInfo who = task.who; - if (who == mCurrentIdler) { - if (DEBUG) { - Slog.i(TAG, "Current idler has finished: " + who); - Slog.i(TAG, "Attributing wakelock to system work source"); - } - mContext.unbindService(mConnection); - startNextIdleServiceTm(); - } else { - Slog.w(TAG, "finish from non-current idle service? " + who); - } - } - - void updateIdleServiceQueueTm() { - if (DEBUG) { - Slog.i(TAG, "Updating idle service queue"); - } - PackageManager pm = mContext.getPackageManager(); - Intent idleIntent = new Intent(IdleService.SERVICE_INTERFACE); - List<ResolveInfo> services = pm.queryIntentServices(idleIntent, 0); - for (ResolveInfo info : services) { - if (info.serviceInfo != null) { - if (IdleService.PERMISSION_BIND.equals(info.serviceInfo.permission)) { - final ComponentName componentName = new ComponentName( - info.serviceInfo.packageName, - info.serviceInfo.name); - if (DEBUG) { - Slog.i(TAG, " - " + componentName); - } - if (!mIdleServices.containsKey(componentName)) { - if (DEBUG) { - Slog.i(TAG, " + not known; adding"); - } - IdleServiceInfo serviceInfo = new IdleServiceInfo(info, componentName); - mIdleServices.put(componentName, serviceInfo); - mIdleServiceQueue.add(serviceInfo); - } - } else { - if (DEBUG) { - Slog.i(TAG, "Idle service " + info.serviceInfo - + " does not have required permission; ignoring"); - } - } - } - } - } - - void startNextIdleServiceTm() { - mWakeLock.setWorkSource(mSystemWorkSource); - - if (mLastIdler == null) { - // we've run the queue; nothing more to do until the next idle interval. - if (DEBUG) { - Slog.i(TAG, "Queue already drained; nothing more to do"); - } - return; - } - - if (DEBUG) { - Slog.i(TAG, "startNextIdleService : last=" + mLastIdler + " cur=" + mCurrentIdler); - if (mIdleServiceQueue.size() > 0) { - int i = 0; - Slog.i(TAG, "Queue (" + mIdleServiceQueue.size() + "):"); - for (IdleServiceInfo info : mIdleServiceQueue) { - Slog.i(TAG, " " + i + " : " + info); - i++; - } - } - } - if (mCurrentIdler != mLastIdler) { - if (mIdleServiceQueue.size() > 0) { - IdleServiceInfo target = mIdleServiceQueue.pop(); - if (DEBUG) { - Slog.i(TAG, "starting next idle service " + target); - } - Intent idleIntent = new Intent(IdleService.SERVICE_INTERFACE); - idleIntent.setComponent(target.componentName); - mCurrentIdler = target; - ActiveTask task = new ActiveTask(target, VERB_BINDING); - scheduleOpTimeoutTm(task); - boolean bindOk = mContext.bindServiceAsUser(idleIntent, mConnection, - Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY, UserHandle.OWNER); - if (!bindOk) { - if (DEBUG) { - Slog.w(TAG, "bindService() to " + target.componentName - + " failed"); - } - } else { - mIdleServiceQueue.add(target); // at the end for next time - if (DEBUG) { Slog.i(TAG, "Attributing wakelock to target uid " + target.uid); } - mWakeLock.setWorkSource(new WorkSource(target.uid)); - } - } else { - // Queue is empty but mLastIdler is non-null -- eeep. Clear *everything* - // and wind up until the next time around. - Slog.e(TAG, "Queue unexpectedly empty; resetting. last=" - + mLastIdler + " cur=" + mCurrentIdler); - mHandler.removeMessages(MSG_TIMEOUT); - mPendingOperations.clear(); - stopIdleMaintenanceTm(); - } - } else { - // we've reached the place we started, so mark the queue as drained - if (DEBUG) { - Slog.i(TAG, "Reached end of queue."); - } - stopIdleMaintenanceTm(); - } - } - - void sendStartIdleTm(IdleServiceInfo who) { - ActiveTask task = new ActiveTask(who, VERB_IDLING); - scheduleOpTimeoutTm(task); - try { - who.service.startIdleMaintenance(mCallback, task.token); - } catch (RemoteException e) { - // We bound to it, but now we can't reach it. Bail and go on to the - // next service. - mContext.unbindService(mConnection); - if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); } - mHandler.removeMessages(MSG_TIMEOUT); - startNextIdleServiceTm(); - } - } - - void sendEndIdleTm(IdleServiceInfo who) { - ActiveTask task = new ActiveTask(who, VERB_ENDING); - scheduleOpTimeoutTm(task); - if (DEBUG) { - Slog.i(TAG, "Sending end-idle to " + who); - } - try { - who.service.stopIdleMaintenance(mCallback, task.token); - } catch (RemoteException e) { - // We bound to it, but now we can't reach it. Bail and go on to the - // next service. - mContext.unbindService(mConnection); - if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); } - mHandler.removeMessages(MSG_TIMEOUT); - startNextIdleServiceTm(); - } - } - - ServiceConnection mConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - if (DEBUG) { - Slog.i(TAG, "onServiceConnected(" + name + ")"); - } - IdleServiceInfo info = mIdleServices.get(name); - if (info != null) { - // Bound! Cancel the bind timeout - mHandler.removeMessages(MSG_TIMEOUT); - // Now tell it to start its idle work - info.service = IIdleService.Stub.asInterface(service); - sendStartIdleTm(info); - } else { - // We bound to a service we don't know about. That's ungood. - Slog.e(TAG, "Connected to unexpected component " + name); - mContext.unbindService(this); - } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - if (DEBUG) { - Slog.i(TAG, "onServiceDisconnected(" + name + ")"); - } - IdleServiceInfo who = mIdleServices.get(name); - if (who == mCurrentIdler) { - // Hm, okay; they didn't tell us they were finished but they - // went away. Crashed, probably. Oh well. They're gone, so - // we can't finish them cleanly; just force things along. - Slog.w(TAG, "Idler unexpectedly vanished: " + mCurrentIdler); - mContext.unbindService(this); - mHandler.removeMessages(MSG_TIMEOUT); - startNextIdleServiceTm(); - } else { - // Not the current idler, so we don't interrupt our process... - if (DEBUG) { - Slog.w(TAG, "Disconnect of abandoned or unexpected service " + name); - } - } - } - }; - - // Schedules a timeout / end-of-work based on the task verb - void scheduleOpTimeoutTm(ActiveTask task) { - final long timeoutMillis = (task.verb == VERB_IDLING) ? IDLE_TIMESLICE : OP_TIMEOUT; - if (DEBUG) { - Slog.i(TAG, "Scheduling timeout (token " + task.token - + " : verb " + task.verb + ") for " + task + " in " + timeoutMillis); - } - mPendingOperations.put(task.token, task); - mHandler.removeMessages(MSG_TIMEOUT); - final Message msg = mHandler.obtainMessage(MSG_TIMEOUT, 0, task.token); - mHandler.sendMessageDelayed(msg, timeoutMillis); - } - - // ------------------------------------------------------------------------------- - public IdleMaintenanceService(Context context, BatteryService batteryService) { - mContext = context; - mBatteryService = batteryService; - - mAlarmService = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - - PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - - mHandler = new IdleHandler(mContext.getMainLooper()); - mCallback = new IdleCallback(); - - Intent intent = new Intent(ACTION_UPDATE_IDLE_MAINTENANCE_STATE); - intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - mUpdateIdleMaintenanceStatePendingIntent = PendingIntent.getBroadcast(mContext, 0, - intent, PendingIntent.FLAG_UPDATE_CURRENT); - - register(mHandler); - } - - public void register(Handler handler) { - IntentFilter intentFilter = new IntentFilter(); - - // Alarm actions. - intentFilter.addAction(ACTION_UPDATE_IDLE_MAINTENANCE_STATE); - - // Battery actions. - intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); - - // Screen actions. - intentFilter.addAction(Intent.ACTION_SCREEN_ON); - intentFilter.addAction(Intent.ACTION_SCREEN_OFF); - - // Dream actions. - intentFilter.addAction(Intent.ACTION_DREAMING_STARTED); - intentFilter.addAction(Intent.ACTION_DREAMING_STOPPED); - - mContext.registerReceiverAsUser(this, UserHandle.ALL, - intentFilter, null, mHandler); - - intentFilter = new IntentFilter(); - intentFilter.addAction(ACTION_FORCE_IDLE_MAINTENANCE); - mContext.registerReceiverAsUser(this, UserHandle.ALL, - intentFilter, android.Manifest.permission.SET_ACTIVITY_WATCHER, mHandler); - } - - private void scheduleUpdateIdleMaintenanceState(long delayMillis) { - final long triggetRealTimeMillis = SystemClock.elapsedRealtime() + delayMillis; - mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggetRealTimeMillis, - mUpdateIdleMaintenanceStatePendingIntent); - } - - private void unscheduleUpdateIdleMaintenanceState() { - mAlarmService.cancel(mUpdateIdleMaintenanceStatePendingIntent); - } - - private void updateIdleMaintenanceStateTm(boolean noisy) { - if (mIdleMaintenanceStarted) { - // Idle maintenance can be interrupted by user activity, or duration - // time out, or low battery. - final boolean batteryOk - = batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning(); - if (!lastUserActivityPermitsIdleMaintenanceRunning() || !batteryOk) { - unscheduleUpdateIdleMaintenanceState(); - mIdleMaintenanceStarted = false; - // We stopped since we don't have enough battery or timed out but the - // user is not using the device, so we should be able to run maintenance - // in the next maintenance window since the battery may be charged - // without interaction and the min interval between maintenances passed. - if (!batteryOk) { - scheduleUpdateIdleMaintenanceState( - getNextIdleMaintenanceIntervalStartFromNow()); - } - - EventLogTags.writeIdleMaintenanceWindowFinish(SystemClock.elapsedRealtime(), - mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(), - isBatteryCharging() ? 1 : 0); - scheduleIdleFinishTm(); - } - } else if (deviceStatePermitsIdleMaintenanceStart(noisy) - && lastUserActivityPermitsIdleMaintenanceStart(noisy) - && lastRunPermitsIdleMaintenanceStart(noisy)) { - // Now that we started idle maintenance, we should schedule another - // update for the moment when the idle maintenance times out. - scheduleUpdateIdleMaintenanceState(MAX_IDLE_MAINTENANCE_DURATION); - mIdleMaintenanceStarted = true; - EventLogTags.writeIdleMaintenanceWindowStart(SystemClock.elapsedRealtime(), - mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(), - isBatteryCharging() ? 1 : 0); - mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime(); - startIdleMaintenanceTm(); - } else if (lastUserActivityPermitsIdleMaintenanceStart(noisy)) { - if (lastRunPermitsIdleMaintenanceStart(noisy)) { - // The user does not use the device and we did not run maintenance in more - // than the min interval between runs, so schedule an update - maybe the - // battery will be charged latter. - scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START); - } else { - // The user does not use the device but we have run maintenance in the min - // interval between runs, so schedule an update after the min interval ends. - scheduleUpdateIdleMaintenanceState( - getNextIdleMaintenanceIntervalStartFromNow()); - } - } - } - - void startIdleMaintenanceTm() { - if (DEBUG) { - Slog.i(TAG, "*** Starting idle maintenance ***"); - } - if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); } - mWakeLock.setWorkSource(mSystemWorkSource); - mWakeLock.acquire(); - updateIdleServiceQueueTm(); - mCurrentIdler = null; - mLastIdler = (mIdleServiceQueue.size() > 0) ? mIdleServiceQueue.peekLast() : null; - startNextIdleServiceTm(); - } - - // Start a graceful wind-down of the idle maintenance state: end the current idler - // and pretend that we've finished running the queue. If there's no current idler, - // this is a no-op. - void scheduleIdleFinishTm() { - if (mCurrentIdler != null) { - if (DEBUG) { - Slog.i(TAG, "*** Finishing idle maintenance ***"); - } - mLastIdler = mCurrentIdler; - sendEndIdleTm(mCurrentIdler); - } else { - if (DEBUG) { - Slog.w(TAG, "Asked to finish idle maintenance but we're done already"); - } - } - } - - // Actual finalization of the idle maintenance sequence - void stopIdleMaintenanceTm() { - if (mLastIdler != null) { - if (DEBUG) { - Slog.i(TAG, "*** Idle maintenance shutdown ***"); - } - mWakeLock.setWorkSource(mSystemWorkSource); - mLastIdler = mCurrentIdler = null; - updateIdleMaintenanceStateTm(false); // resets 'started' and schedules next window - mWakeLock.release(); - } else { - Slog.e(TAG, "ERROR: idle shutdown but invariants not held. last=" + mLastIdler - + " cur=" + mCurrentIdler + " size=" + mIdleServiceQueue.size()); - } - } - - private long getNextIdleMaintenanceIntervalStartFromNow() { - return mLastIdleMaintenanceStartTimeMillis + MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS - - SystemClock.elapsedRealtime(); - } - - private boolean deviceStatePermitsIdleMaintenanceStart(boolean noisy) { - final int minBatteryLevel = isBatteryCharging() - ? MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING - : MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING; - boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID - && mBatteryService.getBatteryLevel() > minBatteryLevel); - if (!allowed && noisy) { - Slog.i("IdleMaintenance", "Idle maintenance not allowed due to power"); - } - return allowed; - } - - private boolean lastUserActivityPermitsIdleMaintenanceStart(boolean noisy) { - // The last time the user poked the device is above the threshold. - boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID - && SystemClock.elapsedRealtime() - mLastUserActivityElapsedTimeMillis - > MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START); - if (!allowed && noisy) { - Slog.i("IdleMaintenance", "Idle maintenance not allowed due to last user activity"); - } - return allowed; - } - - private boolean lastRunPermitsIdleMaintenanceStart(boolean noisy) { - // Enough time passed since the last maintenance run. - boolean allowed = SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis - > MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS; - if (!allowed && noisy) { - Slog.i("IdleMaintenance", "Idle maintenance not allowed due time since last"); - } - return allowed; - } - - private boolean lastUserActivityPermitsIdleMaintenanceRunning() { - // The user is not using the device. - return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID); - } - - private boolean batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning() { - // Battery not too low and the maintenance duration did not timeout. - return (mBatteryService.getBatteryLevel() > MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING - && mLastIdleMaintenanceStartTimeMillis + MAX_IDLE_MAINTENANCE_DURATION - > SystemClock.elapsedRealtime()); - } - - private boolean isBatteryCharging() { - return mBatteryService.getPlugType() > 0 - && mBatteryService.getInvalidCharger() == 0; - } - - @Override - public void onReceive(Context context, Intent intent) { - if (DEBUG) { - Log.i(TAG, intent.getAction()); - } - String action = intent.getAction(); - if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { - // We care about battery only if maintenance is in progress so we can - // stop it if battery is too low. Note that here we assume that the - // maintenance clients are properly holding a wake lock. We will - // refactor the maintenance to use services instead of intents for the - // next release. The only client for this for now is internal an holds - // a wake lock correctly. - if (mIdleMaintenanceStarted) { - updateIdleMaintenanceStateTm(false); - } - } else if (Intent.ACTION_SCREEN_ON.equals(action) - || Intent.ACTION_DREAMING_STOPPED.equals(action)) { - mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID; - // Unschedule any future updates since we already know that maintenance - // cannot be performed since the user is back. - unscheduleUpdateIdleMaintenanceState(); - // If the screen went on/stopped dreaming, we know the user is using the - // device which means that idle maintenance should be stopped if running. - updateIdleMaintenanceStateTm(false); - } else if (Intent.ACTION_SCREEN_OFF.equals(action) - || Intent.ACTION_DREAMING_STARTED.equals(action)) { - mLastUserActivityElapsedTimeMillis = SystemClock.elapsedRealtime(); - // If screen went off/started dreaming, we may be able to start idle maintenance - // after the minimal user inactivity elapses. We schedule an alarm for when - // this timeout elapses since the device may go to sleep by then. - scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START); - } else if (ACTION_UPDATE_IDLE_MAINTENANCE_STATE.equals(action)) { - updateIdleMaintenanceStateTm(false); - } else if (ACTION_FORCE_IDLE_MAINTENANCE.equals(action)) { - long now = SystemClock.elapsedRealtime() - 1; - mLastUserActivityElapsedTimeMillis = now - MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START; - mLastIdleMaintenanceStartTimeMillis = now - MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS; - updateIdleMaintenanceStateTm(true); - } - } -} diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index f2db791..2a7b4f6 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -16,12 +16,13 @@ package com.android.server.pm; -import android.content.BroadcastReceiver; +import android.app.job.JobInfo; +import android.app.job.JobParameters; +import android.app.job.JobScheduler; +import android.app.job.JobService; +import android.content.ComponentName; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.os.ServiceManager; -import android.os.UserHandle; import android.util.Log; import java.util.HashSet; @@ -30,62 +31,63 @@ import java.util.concurrent.atomic.AtomicBoolean; /** * {@hide} */ -public class BackgroundDexOptService { - +public class BackgroundDexOptService extends JobService { static final String TAG = "BackgroundDexOptService"; - private final BroadcastReceiver mIdleMaintenanceReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)) { - onIdleStart(); - } else if (Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) { - onIdleStop(); - } - } - }; - - final PackageManagerService mPackageManager; + static final int BACKGROUND_DEXOPT_JOB = 808; + private static ComponentName sDexoptServiceName = new ComponentName( + BackgroundDexOptService.class.getPackage().getName(), + BackgroundDexOptService.class.getName()); final AtomicBoolean mIdleTime = new AtomicBoolean(false); - public BackgroundDexOptService(Context context) { - mPackageManager = (PackageManagerService)ServiceManager.getService("package"); - - IntentFilter idleMaintenanceFilter = new IntentFilter(); - idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_START); - idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_END); - context.registerReceiverAsUser(mIdleMaintenanceReceiver, UserHandle.ALL, - idleMaintenanceFilter, null, null); + public static void schedule(Context context) { + JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + JobInfo job = new JobInfo.Builder(BACKGROUND_DEXOPT_JOB, sDexoptServiceName) + .setRequiresDeviceIdle(true) + .setRequiresCharging(true) + .build(); + js.schedule(job); } - public boolean onIdleStart() { + @Override + public boolean onStartJob(JobParameters params) { Log.i(TAG, "onIdleStart"); - if (mPackageManager.isStorageLow()) { + final PackageManagerService pm = + (PackageManagerService)ServiceManager.getService("package"); + + if (pm.isStorageLow()) { return false; } - final HashSet<String> pkgs = mPackageManager.getPackagesThatNeedDexOpt(); + final HashSet<String> pkgs = pm.getPackagesThatNeedDexOpt(); if (pkgs == null) { return false; } + + final JobParameters jobParams = params; mIdleTime.set(true); new Thread("BackgroundDexOptService_DexOpter") { @Override public void run() { for (String pkg : pkgs) { if (!mIdleTime.get()) { - break; + // stopped while still working, so we need to reschedule + schedule(BackgroundDexOptService.this); + return; } - mPackageManager.performDexOpt(pkg, false); + pm.performDexOpt(pkg, false); } + // ran to completion, so we abandon our timeslice and do not reschedule + jobFinished(jobParams, false); } }.start(); return true; } - public void onIdleStop() { + @Override + public boolean onStopJob(JobParameters params) { Log.i(TAG, "onIdleStop"); mIdleTime.set(false); + return false; } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 3102cce..04ba2a1 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -933,13 +933,6 @@ public final class SystemServer { } try { - Slog.i(TAG, "IdleMaintenanceService"); - new IdleMaintenanceService(context, battery); - } catch (Throwable e) { - reportWtf("starting IdleMaintenanceService", e); - } - - try { if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) { mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS); } @@ -990,7 +983,7 @@ public final class SystemServer { try { Slog.i(TAG, "BackgroundDexOptService"); - new BackgroundDexOptService(context); + BackgroundDexOptService.schedule(context); } catch (Throwable e) { reportWtf("starting BackgroundDexOptService", e); } diff --git a/tests/IdleServiceTest/Android.mk b/tests/IdleServiceTest/Android.mk deleted file mode 100644 index a7879c5..0000000 --- a/tests/IdleServiceTest/Android.mk +++ /dev/null @@ -1,13 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := tests - -LOCAL_SRC_FILES := $(call all-subdir-java-files) - -LOCAL_PACKAGE_NAME := IdleServiceTest -LOCAL_CERTIFICATE := platform - -LOCAL_PROGUARD_ENABLED := disabled - -include $(BUILD_PACKAGE) diff --git a/tests/IdleServiceTest/AndroidManifest.xml b/tests/IdleServiceTest/AndroidManifest.xml deleted file mode 100644 index 16d2324..0000000 --- a/tests/IdleServiceTest/AndroidManifest.xml +++ /dev/null @@ -1,59 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2014 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.idleservicetest"> - - <application> - <service android:name="TestService" - android:exported="true" - android:enabled="true" - android:permission="android.permission.BIND_IDLE_SERVICE" > - <intent-filter> - <action android:name="android.service.idle.IdleService" /> - </intent-filter> - </service> - - <service android:name="CrashingTestService" - android:exported="true" - android:enabled="true" - android:permission="android.permission.BIND_IDLE_SERVICE" > - <intent-filter> - <action android:name="android.service.idle.IdleService" /> - </intent-filter> - </service> - - <service android:name="TimeoutTestService" - android:exported="true" - android:enabled="true" - android:permission="android.permission.BIND_IDLE_SERVICE" > - <intent-filter> - <action android:name="android.service.idle.IdleService" /> - </intent-filter> - </service> - - <!-- UnpermissionedTestService should never run because it does - not require the necessary permission in its <service> block --> - <service android:name="UnpermissionedTestService" - android:exported="true" - android:enabled="true" > - <intent-filter> - <action android:name="android.service.idle.IdleService" /> - </intent-filter> - </service> - - </application> -</manifest> diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java deleted file mode 100644 index 022ebcf..0000000 --- a/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.idleservicetest; - -import android.app.maintenance.IdleService; -import android.os.Handler; -import android.util.Log; - -public class CrashingTestService extends IdleService { - static final String TAG = "CrashingTestService"; - - String mNull = null; - - @Override - public boolean onIdleStart() { - Log.i(TAG, "Idle maintenance: onIdleStart()"); - - Handler h = new Handler(); - Runnable r = new Runnable() { - @Override - public void run() { - Log.i(TAG, "Explicitly crashing"); - if (mNull.equals("")) { - Log.i(TAG, "won't happen"); - } - } - }; - Log.i(TAG, "Posting explicit crash in 15 seconds"); - h.postDelayed(r, 15 * 1000); - return true; - } - - @Override - public void onIdleStop() { - Log.i(TAG, "Idle maintenance: onIdleStop()"); - } - -} diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java deleted file mode 100644 index 7e9805f..0000000 --- a/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.idleservicetest; - -import android.app.maintenance.IdleService; -import android.os.Handler; -import android.util.Log; - -public class TestService extends IdleService { - static final String TAG = "TestService"; - - @Override - public boolean onIdleStart() { - Log.i(TAG, "Idle maintenance: onIdleStart()"); - - Handler h = new Handler(); - Runnable r = new Runnable() { - @Override - public void run() { - Log.i(TAG, "Explicitly finishing idle"); - finishIdle(); - } - }; - Log.i(TAG, "Posting explicit finish in 15 seconds"); - h.postDelayed(r, 15 * 1000); - return true; - } - - @Override - public void onIdleStop() { - Log.i(TAG, "Idle maintenance: onIdleStop()"); - } - -} diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java deleted file mode 100644 index b2ba21b..0000000 --- a/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.idleservicetest; - -import android.app.maintenance.IdleService; -import android.util.Log; - -public class TimeoutTestService extends IdleService { - private static final String TAG = "TimeoutTestService"; - - @Override - public boolean onIdleStart() { - Log.i(TAG, "onIdleStart() but anticipating time-slice timeout"); - return true; - } - - @Override - public void onIdleStop() { - Log.i(TAG, "onIdleStop() so we're done"); - } - -} diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java deleted file mode 100644 index b9fe32b..0000000 --- a/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.idleservicetest; - -import android.app.maintenance.IdleService; -import android.util.Log; - -// Should never be invoked because its manifest declaration does not -// require the necessary permission. -public class UnpermissionedTestService extends IdleService { - private static final String TAG = "UnpermissionedTestService"; - - @Override - public boolean onIdleStart() { - Log.e(TAG, "onIdleStart() for this service should never be called!"); - return false; - } - - @Override - public void onIdleStop() { - Log.e(TAG, "onIdleStop() for this service should never be called!"); - } - -} |