}
@Override
+ public int scheduleAsPackage(JobInfo job, String packageName, int userId) {
+ try {
+ return mBinder.scheduleAsPackage(job, packageName, userId);
+ } catch (RemoteException e) {
+ return JobScheduler.RESULT_FAILURE;
+ }
+ }
+
+ @Override
public void cancel(int jobId) {
try {
mBinder.cancel(jobId);
*/
interface IJobScheduler {
int schedule(in JobInfo job);
+ int scheduleAsPackage(in JobInfo job, String packageName, int userId);
void cancel(int jobId);
void cancelAll();
List<JobInfo> getAllPendingJobs();
public abstract int schedule(JobInfo job);
/**
+ *
+ * @param job The job to be scheduled.
+ * @param packageName The package on behalf of which the job is to be scheduled. This will be
+ * used to track battery usage and appIdleState.
+ * @param userId User on behalf of whom this job is to be scheduled.
+ * @return {@link #RESULT_SUCCESS} or {@link #RESULT_FAILURE}
+ * @hide
+ */
+ public abstract int scheduleAsPackage(JobInfo job, String packageName, int userId);
+
+ /**
* Cancel a job that is pending in the JobScheduler.
* @param jobId unique identifier for this job. Obtain this value from the jobs returned by
* {@link #getAllPendingJobs()}.
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.Process;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
* @return Result of this operation. See <code>JobScheduler#RESULT_*</code> return codes.
*/
public int schedule(JobInfo job, int uId) {
+ return scheduleAsPackage(job, uId, null, -1);
+ }
+
+ public int scheduleAsPackage(JobInfo job, int uId, String packageName, int userId) {
JobStatus jobStatus = new JobStatus(job, uId);
+ if (packageName != null) {
+ jobStatus.setSource(packageName, userId);
+ }
cancelJob(uId, job.getId());
try {
if (ActivityManagerNative.getDefault().getAppStartMode(uId,
}
@Override
+ public int scheduleAsPackage(JobInfo job, String packageName, int userId)
+ throws RemoteException {
+ if (DEBUG) {
+ Slog.d(TAG, "Scheduling job: " + job.toString() + " on behalf of " + packageName);
+ }
+ final int uid = Binder.getCallingUid();
+ if (uid != Process.SYSTEM_UID) {
+ throw new IllegalArgumentException("Only system process is allowed"
+ + "to set packageName");
+ }
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return JobSchedulerService.this.scheduleAsPackage(job, uid, packageName, userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
public List<JobInfo> getAllPendingJobs() throws RemoteException {
final int uid = Binder.getCallingUid();
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
return false;
}
try {
- mBatteryStats.noteJobStart(job.getName(), job.getUid());
+ mBatteryStats.noteJobStart(job.getName(), job.getSourceUid());
} catch (RemoteException e) {
// Whatever.
}
}
completedJob = mRunningJob;
try {
- mBatteryStats.noteJobFinish(mRunningJob.getName(), mRunningJob.getUid());
+ mBatteryStats.noteJobFinish(mRunningJob.getName(), mRunningJob.getSourceUid());
} catch (RemoteException e) {
// Whatever.
}
out.attribute(null, "jobid", Integer.toString(jobStatus.getJobId()));
out.attribute(null, "package", jobStatus.getServiceComponent().getPackageName());
out.attribute(null, "class", jobStatus.getServiceComponent().getClassName());
+ if (jobStatus.getSourcePackageName() != null) {
+ out.attribute(null, "sourcePackageName", jobStatus.getSourcePackageName());
+ }
+ out.attribute(null, "sourceUserId", String.valueOf(jobStatus.getSourceUserId()));
out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
out.attribute(null, "priority", String.valueOf(jobStatus.getPriority()));
}
private JobStatus restoreJobFromXml(XmlPullParser parser) throws XmlPullParserException,
IOException {
JobInfo.Builder jobBuilder;
- int uid;
+ int uid, userId;
// Read out job identifier attributes and priority.
try {
jobBuilder.setPersisted(true);
uid = Integer.valueOf(parser.getAttributeValue(null, "uid"));
- String priority = parser.getAttributeValue(null, "priority");
- if (priority != null) {
- jobBuilder.setPriority(Integer.valueOf(priority));
+ String val = parser.getAttributeValue(null, "priority");
+ if (val != null) {
+ jobBuilder.setPriority(Integer.valueOf(val));
}
+ val = parser.getAttributeValue(null, "sourceUserId");
+ userId = val == null ? -1 : Integer.valueOf(val);
} catch (NumberFormatException e) {
Slog.e(TAG, "Error parsing job's required fields, skipping");
return null;
}
+ final String sourcePackageName = parser.getAttributeValue(null, "sourcePackageName");
+
int eventType;
// Read out constraints tag.
do {
jobBuilder.setExtras(extras);
parser.nextTag(); // Consume </extras>
- return new JobStatus(
+ JobStatus js = new JobStatus(
jobBuilder.build(), uid, elapsedRuntimes.first, elapsedRuntimes.second);
+ if (userId != -1) {
+ js.setSource(sourcePackageName, userId);
+ }
+ return js;
}
private JobInfo.Builder buildBuilderFromXml(XmlPullParser parser) throws NumberFormatException {
public void maybeStartTrackingJob(JobStatus jobStatus) {
synchronized (mTrackedTasks) {
mTrackedTasks.add(jobStatus);
- String packageName = jobStatus.job.getService().getPackageName();
+ String packageName = jobStatus.getSourcePackageName();
final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
- jobStatus.uId, jobStatus.getUserId());
+ jobStatus.getSourceUid(), jobStatus.getSourceUserId());
if (DEBUG) {
Slog.d(LOG_TAG, "Start tracking, setting idle state of "
+ packageName + " to " + appIdle);
pw.println("Parole On: " + mAppIdleParoleOn);
synchronized (mTrackedTasks) {
for (JobStatus task : mTrackedTasks) {
- pw.print(task.job.getService().getPackageName());
+ pw.print(task.getSourcePackageName());
pw.print(":idle=" + !task.appNotIdleConstraintSatisfied.get());
pw.print(", ");
}
}
mAppIdleParoleOn = isAppIdleParoleOn;
for (JobStatus task : mTrackedTasks) {
- String packageName = task.job.getService().getPackageName();
+ String packageName = task.getSourcePackageName();
final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
- task.uId, task.getUserId());
+ task.getSourceUid(), task.getSourceUserId());
if (DEBUG) {
Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle);
}
return;
}
for (JobStatus task : mTrackedTasks) {
- if (task.job.getService().getPackageName().equals(packageName)
- && task.getUserId() == userId) {
+ if (task.getSourcePackageName().equals(packageName)
+ && task.getSourceUserId() == userId) {
if (task.appNotIdleConstraintSatisfied.get() != !idle) {
if (DEBUG) {
Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
package com.android.server.job.controllers;
+import android.app.AppGlobals;
import android.app.job.JobInfo;
import android.content.ComponentName;
import android.os.PersistableBundle;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.text.format.DateUtils;
final String name;
final String tag;
+ String sourcePackageName;
+ int sourceUserId = -1;
+ int sourceUid = -1;
+
// Constraints.
final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
final AtomicBoolean timeDelayConstraintSatisfied = new AtomicBoolean();
private JobStatus(JobInfo job, int uId, int numFailures) {
this.job = job;
this.uId = uId;
+ this.sourceUid = uId;
this.name = job.getService().flattenToShortString();
this.tag = "*job*/" + this.name;
this.numFailures = numFailures;
return job.getService();
}
+ public String getSourcePackageName() {
+ return sourcePackageName != null ? sourcePackageName : job.getService().getPackageName();
+ }
+
+ public int getSourceUid() {
+ return sourceUid;
+ }
+
+ public int getSourceUserId() {
+ if (sourceUserId == -1) {
+ sourceUserId = getUserId();
+ }
+ return sourceUserId;
+ }
+
public int getUserId() {
return UserHandle.getUserId(uId);
}
public PersistableBundle getExtras() {
return job.getExtras();
}
-
+
public int getPriority() {
return job.getPriority();
}
}
}
+ public void setSource(String sourcePackageName, int sourceUserId) {
+ this.sourcePackageName = sourcePackageName;
+ this.sourceUserId = sourceUserId;
+ try {
+ sourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
+ sourceUserId);
+ } catch (RemoteException ex) {
+ // Can't happen, PackageManager runs in the same process.
+ }
+ if (sourceUid == -1) {
+ sourceUid = uId;
+ this.sourceUserId = getUserId();
+ this.sourcePackageName = null;
+ }
+ }
+
/**
* Convenience function to identify a job uniquely without pulling all the data that
* {@link #toString()} returns.