Merge "Switch framework to using new scheduled-work API" into lmp-preview-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d478a3a0d8
@@ -1754,12 +1754,13 @@
|
||||
android:label="@string/permlab_recovery"
|
||||
android:description="@string/permdesc_recovery" />
|
||||
|
||||
<!-- Allows the system to bind to an application's idle services
|
||||
<!-- Allows the system to bind to an application's task services
|
||||
@hide -->
|
||||
<permission android:name="android.permission.BIND_IDLE_SERVICE"
|
||||
<permission android:name="android.permission.BIND_TASK_SERVICE"
|
||||
android:protectionLevel="signature"
|
||||
android:label="@string/permlab_bindIdleService"
|
||||
android:description="@string/permdesc_bindIdleService" />
|
||||
android:label="@string/permlab_bindTaskService"
|
||||
android:description="@string/permdesc_bindTaskService" />
|
||||
<uses-permission android:name="android.permission.BIND_TASK_SERVICE"/>
|
||||
|
||||
<!-- ========================================= -->
|
||||
<!-- Permissions for special development tools -->
|
||||
@@ -2875,10 +2876,7 @@
|
||||
|
||||
<service android:name="com.android.server.MountServiceIdler"
|
||||
android:exported="false"
|
||||
android:permission="android.permission.BIND_IDLE_SERVICE" >
|
||||
<intent-filter>
|
||||
<action android:name="android.service.idle.IdleService" />
|
||||
</intent-filter>
|
||||
android:permission="android.permission.BIND_TASK_SERVICE" >
|
||||
</service>
|
||||
|
||||
</application>
|
||||
|
||||
@@ -1260,11 +1260,11 @@
|
||||
<!-- Title of a permission that is never presented to the user. This is not a
|
||||
permission that an application must be granted by the user. Instead, it
|
||||
is part of a mechanism that applications use to indicate to the system
|
||||
that they want to do occasional work while the device is idle. -->
|
||||
<string name="permlab_bindIdleService">run application during idle time</string>
|
||||
that they want to do scheduled background work. -->
|
||||
<string name="permlab_bindTaskService">run the application\'s scheduled background work</string>
|
||||
<!-- Description of an application permission, so that the user can understand
|
||||
what is being done if they are curious. -->
|
||||
<string name="permdesc_bindIdleService">This permission allows the Android system to run the application in the background while the device is not in use.</string>
|
||||
<string name="permdesc_bindTaskService">This permission allows the Android system to run the application in the background when requested.</string>
|
||||
|
||||
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||
<string name="permlab_diagnostic">read/write to resources owned by diag</string>
|
||||
|
||||
@@ -629,6 +629,11 @@ class MountService extends IMountService.Stub
|
||||
sendUmsIntent(true);
|
||||
mSendUmsConnectedOnBoot = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start scheduling nominally-daily fstrim operations
|
||||
*/
|
||||
MountServiceIdler.scheduleIdlePass(mContext);
|
||||
}
|
||||
|
||||
private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
|
||||
|
||||
@@ -16,34 +16,94 @@
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import android.app.maintenance.IdleService;
|
||||
import java.util.Calendar;
|
||||
|
||||
import android.app.task.Task;
|
||||
import android.app.task.TaskManager;
|
||||
import android.app.task.TaskParams;
|
||||
import android.app.task.TaskService;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.util.Slog;
|
||||
|
||||
public class MountServiceIdler extends IdleService {
|
||||
public class MountServiceIdler extends TaskService {
|
||||
private static final String TAG = "MountServiceIdler";
|
||||
|
||||
private static ComponentName sIdleService =
|
||||
new ComponentName(MountServiceIdler.class.getPackage().getName(),
|
||||
MountServiceIdler.class.getName());
|
||||
|
||||
private static int MOUNT_TASK_ID = 808;
|
||||
|
||||
private boolean mStarted;
|
||||
private TaskParams mTaskParams;
|
||||
private Runnable mFinishCallback = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Slog.i(TAG, "Got mount service completion callback");
|
||||
finishIdle();
|
||||
synchronized (mFinishCallback) {
|
||||
if (mStarted) {
|
||||
taskFinished(mTaskParams, false);
|
||||
mStarted = false;
|
||||
}
|
||||
}
|
||||
// ... and try again tomorrow
|
||||
scheduleIdlePass(MountServiceIdler.this);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean onIdleStart() {
|
||||
public boolean onStartTask(TaskParams params) {
|
||||
// The mount service will run an fstrim operation asynchronously
|
||||
// on a designated separate thread, so we provide it with a callback
|
||||
// that lets us cleanly end our idle timeslice. It's safe to call
|
||||
// finishIdle() from any thread.
|
||||
mTaskParams = params;
|
||||
MountService ms = MountService.sSelf;
|
||||
if (ms != null) {
|
||||
synchronized (mFinishCallback) {
|
||||
mStarted = true;
|
||||
}
|
||||
ms.runIdleMaintenance(mFinishCallback);
|
||||
}
|
||||
return ms != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIdleStop() {
|
||||
public boolean onStopTask(TaskParams params) {
|
||||
// Once we kick off the fstrim we aren't actually interruptible; just note
|
||||
// that we don't need to call taskFinished(), and let everything happen in
|
||||
// the callback from the mount service.
|
||||
synchronized (mFinishCallback) {
|
||||
mStarted = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule the idle job that will ping the mount service
|
||||
*/
|
||||
public static void scheduleIdlePass(Context context) {
|
||||
TaskManager tm = (TaskManager) context.getSystemService(Context.TASK_SERVICE);
|
||||
|
||||
Calendar calendar = tomorrowMidnight();
|
||||
final long timeToMidnight = calendar.getTimeInMillis() - System.currentTimeMillis();
|
||||
|
||||
Task.Builder builder = new Task.Builder(MOUNT_TASK_ID, sIdleService);
|
||||
builder.setRequiresDeviceIdle(true);
|
||||
builder.setRequiresCharging(true);
|
||||
builder.setMinimumLatency(timeToMidnight);
|
||||
tm.schedule(builder.build());
|
||||
}
|
||||
|
||||
private static Calendar tomorrowMidnight() {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(System.currentTimeMillis());
|
||||
calendar.set(Calendar.HOUR, 0);
|
||||
calendar.set(Calendar.MINUTE, 0);
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
calendar.add(Calendar.DAY_OF_MONTH, 1);
|
||||
return calendar;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,14 @@ import android.app.task.ITaskManager;
|
||||
import android.app.task.Task;
|
||||
import android.app.task.TaskManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.app.task.TaskService;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
@@ -608,24 +612,43 @@ public class TaskManagerService extends com.android.server.SystemService
|
||||
*/
|
||||
private final SparseArray<Boolean> mPersistCache = new SparseArray<Boolean>();
|
||||
|
||||
// Determine whether the caller is allowed to persist tasks, with a small cache
|
||||
// because the lookup is expensive enough that we'd like to avoid repeating it.
|
||||
// This must be called from within the calling app's binder identity!
|
||||
private boolean canCallerPersistTasks() {
|
||||
// Enforce that only the app itself (or shared uid participant) can schedule a
|
||||
// task that runs one of the app's services, as well as verifying that the
|
||||
// named service properly requires the BIND_TASK_SERVICE permission
|
||||
private void enforceValidJobRequest(int uid, Task job) {
|
||||
final PackageManager pm = getContext().getPackageManager();
|
||||
final ComponentName service = job.getService();
|
||||
try {
|
||||
ServiceInfo si = pm.getServiceInfo(service, 0);
|
||||
if (si.applicationInfo.uid != uid) {
|
||||
throw new IllegalArgumentException("uid " + uid +
|
||||
" cannot schedule job in " + service.getPackageName());
|
||||
}
|
||||
if (!TaskService.PERMISSION_BIND.equals(si.permission)) {
|
||||
throw new IllegalArgumentException("Scheduled service " + service
|
||||
+ " does not require android.permission.BIND_TASK_SERVICE permission");
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
throw new IllegalArgumentException("No such service: " + service);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canPersistJobs(int pid, int uid) {
|
||||
// If we get this far we're good to go; all we need to do now is check
|
||||
// whether the app is allowed to persist its scheduled work.
|
||||
final boolean canPersist;
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
synchronized (mPersistCache) {
|
||||
Boolean cached = mPersistCache.get(callingUid);
|
||||
Boolean cached = mPersistCache.get(uid);
|
||||
if (cached != null) {
|
||||
canPersist = cached.booleanValue();
|
||||
} else {
|
||||
// Persisting tasks is tantamount to running at boot, so we permit
|
||||
// it when the app has declared that it uses the RECEIVE_BOOT_COMPLETED
|
||||
// permission
|
||||
int result = getContext().checkCallingPermission(
|
||||
android.Manifest.permission.RECEIVE_BOOT_COMPLETED);
|
||||
int result = getContext().checkPermission(
|
||||
android.Manifest.permission.RECEIVE_BOOT_COMPLETED, pid, uid);
|
||||
canPersist = (result == PackageManager.PERMISSION_GRANTED);
|
||||
mPersistCache.put(callingUid, canPersist);
|
||||
mPersistCache.put(uid, canPersist);
|
||||
}
|
||||
}
|
||||
return canPersist;
|
||||
@@ -637,9 +660,12 @@ public class TaskManagerService extends com.android.server.SystemService
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Scheduling task: " + task);
|
||||
}
|
||||
final boolean canPersist = canCallerPersistTasks();
|
||||
final int pid = Binder.getCallingPid();
|
||||
final int uid = Binder.getCallingUid();
|
||||
|
||||
enforceValidJobRequest(uid, task);
|
||||
final boolean canPersist = canPersistJobs(pid, uid);
|
||||
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return TaskManagerService.this.schedule(task, uid, canPersist);
|
||||
|
||||
Reference in New Issue
Block a user