Loading apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +4 −2 Original line number Diff line number Diff line Loading @@ -1631,7 +1631,8 @@ public class JobSchedulerService extends com.android.server.SystemService jobStatus.getEstimatedNetworkDownloadBytes(), jobStatus.getEstimatedNetworkUploadBytes(), jobStatus.getWorkCount(), ActivityManager.processStateAmToProto(mUidProcStates.get(jobStatus.getUid()))); ActivityManager.processStateAmToProto(mUidProcStates.get(jobStatus.getUid())), jobStatus.getNamespaceHash()); // If the job is immediately ready to run, then we can just immediately // put it in the pending list and try to schedule it. This is especially Loading Loading @@ -2059,7 +2060,8 @@ public class JobSchedulerService extends com.android.server.SystemService cancelled.getEstimatedNetworkDownloadBytes(), cancelled.getEstimatedNetworkUploadBytes(), cancelled.getWorkCount(), ActivityManager.processStateAmToProto(mUidProcStates.get(cancelled.getUid()))); ActivityManager.processStateAmToProto(mUidProcStates.get(cancelled.getUid())), cancelled.getNamespaceHash()); } // If this is a replacement, bring in the new version of the job if (incomingJob != null) { Loading apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +4 −2 Original line number Diff line number Diff line Loading @@ -499,7 +499,8 @@ public final class JobServiceContext implements ServiceConnection { job.getEstimatedNetworkDownloadBytes(), job.getEstimatedNetworkUploadBytes(), job.getWorkCount(), ActivityManager.processStateAmToProto(mService.getUidProcState(job.getUid()))); ActivityManager.processStateAmToProto(mService.getUidProcState(job.getUid())), job.getNamespaceHash()); sEnqueuedJwiAtJobStart.logSampleWithUid(job.getUid(), job.getWorkCount()); final String sourcePackage = job.getSourcePackageName(); if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) { Loading Loading @@ -1557,7 +1558,8 @@ public final class JobServiceContext implements ServiceConnection { completedJob.getEstimatedNetworkUploadBytes(), completedJob.getWorkCount(), ActivityManager .processStateAmToProto(mService.getUidProcState(completedJob.getUid()))); .processStateAmToProto(mService.getUidProcState(completedJob.getUid())), completedJob.getNamespaceHash()); if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) { Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_SYSTEM_SERVER, "JobScheduler", getId()); Loading apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +70 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.provider.MediaStore; import android.text.format.DateFormat; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IndentingPrintWriter; import android.util.Pair; Loading @@ -51,6 +52,7 @@ import android.util.Slog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; Loading @@ -65,10 +67,12 @@ import com.android.server.job.JobStatusShortInfoProto; import dalvik.annotation.optimization.NeverCompile; import java.io.PrintWriter; import java.security.MessageDigest; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Objects; import java.util.Random; import java.util.function.Predicate; /** Loading @@ -88,6 +92,13 @@ public final class JobStatus { private static final String TAG = "JobScheduler.JobStatus"; static final boolean DEBUG = JobSchedulerService.DEBUG; private static MessageDigest sMessageDigest; /** Cache of namespace to hash to reduce how often we need to generate the namespace hash. */ @GuardedBy("sNamespaceHashCache") private static final ArrayMap<String, String> sNamespaceHashCache = new ArrayMap<>(); /** Maximum size of {@link #sNamespaceHashCache}. */ private static final int MAX_NAMESPACE_CACHE_SIZE = 128; private static final int NUM_CONSTRAINT_CHANGE_HISTORY = 10; public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE; Loading Loading @@ -231,6 +242,8 @@ public final class JobStatus { final String sourceTag; @Nullable private final String mNamespace; @Nullable private final String mNamespaceHash; /** An ID that can be used to uniquely identify the job when logging statsd metrics. */ private final long mLoggingJobId; Loading Loading @@ -570,6 +583,7 @@ public final class JobStatus { this.callingUid = callingUid; this.standbyBucket = standbyBucket; mNamespace = namespace; mNamespaceHash = generateNamespaceHash(namespace); mLoggingJobId = generateLoggingId(namespace, job.getId()); int tempSourceUid = -1; Loading Loading @@ -814,6 +828,56 @@ public final class JobStatus { return ((long) namespace.hashCode()) << 31 | jobId; } @Nullable private static String generateNamespaceHash(@Nullable String namespace) { if (namespace == null) { return null; } if (namespace.trim().isEmpty()) { // Input is composed of all spaces (or nothing at all). return namespace; } synchronized (sNamespaceHashCache) { final int idx = sNamespaceHashCache.indexOfKey(namespace); if (idx >= 0) { return sNamespaceHashCache.valueAt(idx); } } String hash = null; try { // .hashCode() can result in conflicts that would make distinguishing between // namespaces hard and reduce the accuracy of certain metrics. Use SHA-256 // to generate the hash since the probability of collision is extremely low. if (sMessageDigest == null) { sMessageDigest = MessageDigest.getInstance("SHA-256"); } final byte[] digest = sMessageDigest.digest(namespace.getBytes()); // Convert to hexadecimal representation StringBuilder hexBuilder = new StringBuilder(digest.length); for (byte byteChar : digest) { hexBuilder.append(String.format("%02X", byteChar)); } hash = hexBuilder.toString(); } catch (Exception e) { Slog.wtf(TAG, "Couldn't hash input", e); } if (hash == null) { // If we get to this point, something went wrong with the MessageDigest above. // Don't return the raw input value (which would defeat the purpose of hashing). return "failed_namespace_hash"; } hash = hash.intern(); synchronized (sNamespaceHashCache) { if (sNamespaceHashCache.size() >= MAX_NAMESPACE_CACHE_SIZE) { // Drop a random mapping instead of dropping at a predefined index to avoid // potentially always dropping the same mapping. sNamespaceHashCache.removeAt((new Random()).nextInt(MAX_NAMESPACE_CACHE_SIZE)); } sNamespaceHashCache.put(namespace, hash); } return hash; } public void enqueueWorkLocked(JobWorkItem work) { if (pendingWork == null) { pendingWork = new ArrayList<>(); Loading Loading @@ -1117,10 +1181,16 @@ public final class JobStatus { return true; } @Nullable public String getNamespace() { return mNamespace; } @Nullable public String getNamespaceHash() { return mNamespaceHash; } public String getSourceTag() { return sourceTag; } Loading Loading
apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +4 −2 Original line number Diff line number Diff line Loading @@ -1631,7 +1631,8 @@ public class JobSchedulerService extends com.android.server.SystemService jobStatus.getEstimatedNetworkDownloadBytes(), jobStatus.getEstimatedNetworkUploadBytes(), jobStatus.getWorkCount(), ActivityManager.processStateAmToProto(mUidProcStates.get(jobStatus.getUid()))); ActivityManager.processStateAmToProto(mUidProcStates.get(jobStatus.getUid())), jobStatus.getNamespaceHash()); // If the job is immediately ready to run, then we can just immediately // put it in the pending list and try to schedule it. This is especially Loading Loading @@ -2059,7 +2060,8 @@ public class JobSchedulerService extends com.android.server.SystemService cancelled.getEstimatedNetworkDownloadBytes(), cancelled.getEstimatedNetworkUploadBytes(), cancelled.getWorkCount(), ActivityManager.processStateAmToProto(mUidProcStates.get(cancelled.getUid()))); ActivityManager.processStateAmToProto(mUidProcStates.get(cancelled.getUid())), cancelled.getNamespaceHash()); } // If this is a replacement, bring in the new version of the job if (incomingJob != null) { Loading
apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +4 −2 Original line number Diff line number Diff line Loading @@ -499,7 +499,8 @@ public final class JobServiceContext implements ServiceConnection { job.getEstimatedNetworkDownloadBytes(), job.getEstimatedNetworkUploadBytes(), job.getWorkCount(), ActivityManager.processStateAmToProto(mService.getUidProcState(job.getUid()))); ActivityManager.processStateAmToProto(mService.getUidProcState(job.getUid())), job.getNamespaceHash()); sEnqueuedJwiAtJobStart.logSampleWithUid(job.getUid(), job.getWorkCount()); final String sourcePackage = job.getSourcePackageName(); if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) { Loading Loading @@ -1557,7 +1558,8 @@ public final class JobServiceContext implements ServiceConnection { completedJob.getEstimatedNetworkUploadBytes(), completedJob.getWorkCount(), ActivityManager .processStateAmToProto(mService.getUidProcState(completedJob.getUid()))); .processStateAmToProto(mService.getUidProcState(completedJob.getUid())), completedJob.getNamespaceHash()); if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) { Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_SYSTEM_SERVER, "JobScheduler", getId()); Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +70 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.provider.MediaStore; import android.text.format.DateFormat; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IndentingPrintWriter; import android.util.Pair; Loading @@ -51,6 +52,7 @@ import android.util.Slog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; Loading @@ -65,10 +67,12 @@ import com.android.server.job.JobStatusShortInfoProto; import dalvik.annotation.optimization.NeverCompile; import java.io.PrintWriter; import java.security.MessageDigest; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Objects; import java.util.Random; import java.util.function.Predicate; /** Loading @@ -88,6 +92,13 @@ public final class JobStatus { private static final String TAG = "JobScheduler.JobStatus"; static final boolean DEBUG = JobSchedulerService.DEBUG; private static MessageDigest sMessageDigest; /** Cache of namespace to hash to reduce how often we need to generate the namespace hash. */ @GuardedBy("sNamespaceHashCache") private static final ArrayMap<String, String> sNamespaceHashCache = new ArrayMap<>(); /** Maximum size of {@link #sNamespaceHashCache}. */ private static final int MAX_NAMESPACE_CACHE_SIZE = 128; private static final int NUM_CONSTRAINT_CHANGE_HISTORY = 10; public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE; Loading Loading @@ -231,6 +242,8 @@ public final class JobStatus { final String sourceTag; @Nullable private final String mNamespace; @Nullable private final String mNamespaceHash; /** An ID that can be used to uniquely identify the job when logging statsd metrics. */ private final long mLoggingJobId; Loading Loading @@ -570,6 +583,7 @@ public final class JobStatus { this.callingUid = callingUid; this.standbyBucket = standbyBucket; mNamespace = namespace; mNamespaceHash = generateNamespaceHash(namespace); mLoggingJobId = generateLoggingId(namespace, job.getId()); int tempSourceUid = -1; Loading Loading @@ -814,6 +828,56 @@ public final class JobStatus { return ((long) namespace.hashCode()) << 31 | jobId; } @Nullable private static String generateNamespaceHash(@Nullable String namespace) { if (namespace == null) { return null; } if (namespace.trim().isEmpty()) { // Input is composed of all spaces (or nothing at all). return namespace; } synchronized (sNamespaceHashCache) { final int idx = sNamespaceHashCache.indexOfKey(namespace); if (idx >= 0) { return sNamespaceHashCache.valueAt(idx); } } String hash = null; try { // .hashCode() can result in conflicts that would make distinguishing between // namespaces hard and reduce the accuracy of certain metrics. Use SHA-256 // to generate the hash since the probability of collision is extremely low. if (sMessageDigest == null) { sMessageDigest = MessageDigest.getInstance("SHA-256"); } final byte[] digest = sMessageDigest.digest(namespace.getBytes()); // Convert to hexadecimal representation StringBuilder hexBuilder = new StringBuilder(digest.length); for (byte byteChar : digest) { hexBuilder.append(String.format("%02X", byteChar)); } hash = hexBuilder.toString(); } catch (Exception e) { Slog.wtf(TAG, "Couldn't hash input", e); } if (hash == null) { // If we get to this point, something went wrong with the MessageDigest above. // Don't return the raw input value (which would defeat the purpose of hashing). return "failed_namespace_hash"; } hash = hash.intern(); synchronized (sNamespaceHashCache) { if (sNamespaceHashCache.size() >= MAX_NAMESPACE_CACHE_SIZE) { // Drop a random mapping instead of dropping at a predefined index to avoid // potentially always dropping the same mapping. sNamespaceHashCache.removeAt((new Random()).nextInt(MAX_NAMESPACE_CACHE_SIZE)); } sNamespaceHashCache.put(namespace, hash); } return hash; } public void enqueueWorkLocked(JobWorkItem work) { if (pendingWork == null) { pendingWork = new ArrayList<>(); Loading Loading @@ -1117,10 +1181,16 @@ public final class JobStatus { return true; } @Nullable public String getNamespace() { return mNamespace; } @Nullable public String getNamespaceHash() { return mNamespaceHash; } public String getSourceTag() { return sourceTag; } Loading