summaryrefslogtreecommitdiff
path: root/apex
diff options
context:
space:
mode:
Diffstat (limited to 'apex')
-rw-r--r--apex/Android.bp41
-rw-r--r--apex/blobstore/TEST_MAPPING8
-rw-r--r--apex/blobstore/framework/java/android/app/blob/BlobHandle.java62
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java11
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java395
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java111
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java74
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java9
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java10
-rw-r--r--apex/media/framework/Android.bp59
-rw-r--r--apex/permission/framework/Android.bp59
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java3
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java3
-rw-r--r--apex/permission/service/java/com/android/role/persistence/RolesPersistence.java3
-rw-r--r--apex/permission/service/java/com/android/role/persistence/RolesState.java3
-rw-r--r--apex/sdkextensions/framework/Android.bp58
-rw-r--r--apex/statsd/Android.bp35
-rw-r--r--apex/statsd/aidl/android/os/IStatsCompanionService.aidl7
-rw-r--r--apex/statsd/framework/Android.bp78
-rw-r--r--apex/statsd/framework/java/android/os/StatsDimensionsValue.java354
-rw-r--r--apex/statsd/jni/android_util_StatsLog.cpp80
-rw-r--r--apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java5
22 files changed, 1265 insertions, 203 deletions
diff --git a/apex/Android.bp b/apex/Android.bp
index abebfa39fada..362cf95b3832 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -29,6 +29,16 @@ mainline_stubs_args =
// TODO: remove this server classes are cleaned up.
mainline_stubs_args += "--hide-package com.android.server "
+priv_apps = " " +
+ "--show-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," +
+ "\\) "
+
+module_libs = " " +
+ " --show-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES," +
+ "\\) "
+
stubs_defaults {
name: "framework-module-stubs-defaults-publicapi",
args: mainline_stubs_args,
@@ -37,36 +47,23 @@ stubs_defaults {
stubs_defaults {
name: "framework-module-stubs-defaults-systemapi",
- args: mainline_stubs_args +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\) ",
+ args: mainline_stubs_args + priv_apps,
installable: false,
}
+// The defaults for module_libs comes in two parts - defaults for API checks
+// and defaults for stub generation. This is because we want the API txt
+// files to *only* include the module_libs_api, but the stubs to include
+// module_libs_api as well as priv_apps.
+
stubs_defaults {
- name: "framework-module-stubs-defaults-module_apps_api",
- args: mainline_stubs_args +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\) " +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.MODULE_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\) ",
+ name: "framework-module-api-defaults-module_libs_api",
+ args: mainline_stubs_args + module_libs,
installable: false,
}
stubs_defaults {
name: "framework-module-stubs-defaults-module_libs_api",
- args: mainline_stubs_args +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\) " +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.MODULE_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\) " +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES," +
- "process=android.annotation.SystemApi.Process.ALL\\) ",
+ args: mainline_stubs_args + module_libs + priv_apps,
installable: false,
}
diff --git a/apex/blobstore/TEST_MAPPING b/apex/blobstore/TEST_MAPPING
index 4dc0c49380c8..cfe19a530b27 100644
--- a/apex/blobstore/TEST_MAPPING
+++ b/apex/blobstore/TEST_MAPPING
@@ -2,6 +2,14 @@
"presubmit": [
{
"name": "CtsBlobStoreTestCases"
+ },
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.blob"
+ }
+ ]
}
]
} \ No newline at end of file
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
index f7e6a987ded3..f110b36c7e90 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
@@ -45,6 +45,10 @@ import java.util.Objects;
public final class BlobHandle implements Parcelable {
private static final String ALGO_SHA_256 = "SHA-256";
+ private static final String[] SUPPORTED_ALGOS = {
+ ALGO_SHA_256
+ };
+
private static final int LIMIT_BLOB_TAG_LENGTH = 128; // characters
/**
@@ -104,14 +108,9 @@ public final class BlobHandle implements Parcelable {
public static @NonNull BlobHandle create(@NonNull String algorithm, @NonNull byte[] digest,
@NonNull CharSequence label, @CurrentTimeMillisLong long expiryTimeMillis,
@NonNull String tag) {
- Preconditions.checkNotNull(algorithm, "algorithm must not be null");
- Preconditions.checkNotNull(digest, "digest must not be null");
- Preconditions.checkNotNull(label, "label must not be null");
- Preconditions.checkArgumentNonnegative(expiryTimeMillis,
- "expiryTimeMillis must not be negative");
- Preconditions.checkNotNull(tag, "tag must not be null");
- Preconditions.checkArgument(tag.length() <= LIMIT_BLOB_TAG_LENGTH, "tag too long");
- return new BlobHandle(algorithm, digest, label, expiryTimeMillis, tag);
+ final BlobHandle handle = new BlobHandle(algorithm, digest, label, expiryTimeMillis, tag);
+ handle.assertIsValid();
+ return handle;
}
/**
@@ -215,12 +214,47 @@ public final class BlobHandle implements Parcelable {
}
/** @hide */
- public void dump(IndentingPrintWriter fout) {
- fout.println("algo: " + algorithm);
- fout.println("digest: " + Base64.encodeToString(digest, Base64.NO_WRAP));
- fout.println("label: " + label);
- fout.println("expiryMs: " + expiryTimeMillis);
- fout.println("tag: " + tag);
+ public void dump(IndentingPrintWriter fout, boolean dumpFull) {
+ if (dumpFull) {
+ fout.println("algo: " + algorithm);
+ fout.println("digest: " + (dumpFull ? encodeDigest() : safeDigest()));
+ fout.println("label: " + label);
+ fout.println("expiryMs: " + expiryTimeMillis);
+ fout.println("tag: " + tag);
+ } else {
+ fout.println(toString());
+ }
+ }
+
+ /** @hide */
+ public void assertIsValid() {
+ Preconditions.checkArgumentIsSupported(SUPPORTED_ALGOS, algorithm);
+ Preconditions.checkByteArrayNotEmpty(digest, "digest");
+ Preconditions.checkStringNotEmpty(label, "label must not be null");
+ Preconditions.checkArgumentNonnegative(expiryTimeMillis,
+ "expiryTimeMillis must not be negative");
+ Preconditions.checkStringNotEmpty(tag, "tag must not be null");
+ Preconditions.checkArgument(tag.length() <= LIMIT_BLOB_TAG_LENGTH, "tag too long");
+ }
+
+ @Override
+ public String toString() {
+ return "BlobHandle {"
+ + "algo:" + algorithm + ","
+ + "digest:" + safeDigest() + ","
+ + "label:" + label + ","
+ + "expiryMs:" + expiryTimeMillis + ","
+ + "tag:" + tag
+ + "}";
+ }
+
+ private String safeDigest() {
+ final String digestStr = encodeDigest();
+ return digestStr.substring(0, 2) + ".." + digestStr.substring(digestStr.length() - 2);
+ }
+
+ private String encodeDigest() {
+ return Base64.encodeToString(digest, Base64.NO_WRAP);
}
public static final @NonNull Creator<BlobHandle> CREATOR = new Creator<BlobHandle>() {
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
index e9838d6b9712..aba3e8cadfa3 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -48,6 +48,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
+import com.android.server.blob.BlobStoreManagerService.DumpArgs;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -156,6 +157,12 @@ class BlobMetadata {
}
}
+ boolean hasLeases() {
+ synchronized (mMetadataLock) {
+ return mLeasees.isEmpty();
+ }
+ }
+
boolean isAccessAllowedForCaller(String callingPackage, int callingUid) {
// TODO: verify blob is still valid (expiryTime is not elapsed)
synchronized (mMetadataLock) {
@@ -234,10 +241,10 @@ class BlobMetadata {
return revocableFd.getRevocableFileDescriptor();
}
- void dump(IndentingPrintWriter fout) {
+ void dump(IndentingPrintWriter fout, DumpArgs dumpArgs) {
fout.println("blobHandle:");
fout.increaseIndent();
- blobHandle.dump(fout);
+ blobHandle.dump(fout, dumpArgs.shouldDumpFull());
fout.decreaseIndent();
fout.println("Committers:");
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index fcc30e30dfaa..13f095e5a503 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -40,6 +40,7 @@ import android.annotation.IdRes;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.blob.BlobHandle;
import android.app.blob.IBlobStoreManager;
import android.app.blob.IBlobStoreSession;
@@ -49,6 +50,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManagerInternal;
+import android.content.res.ResourceId;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
@@ -67,6 +69,8 @@ import android.util.SparseArray;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
@@ -91,6 +95,7 @@ import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Service responsible for maintaining and facilitating access to data blobs published by apps.
@@ -112,20 +117,35 @@ public class BlobStoreManagerService extends SystemService {
private final Context mContext;
private final Handler mHandler;
+ private final Injector mInjector;
private final SessionStateChangeListener mSessionStateChangeListener =
new SessionStateChangeListener();
private PackageManagerInternal mPackageManagerInternal;
+ private final Runnable mSaveBlobsInfoRunnable = this::writeBlobsInfo;
+ private final Runnable mSaveSessionsRunnable = this::writeBlobSessions;
+
public BlobStoreManagerService(Context context) {
+ this(context, new Injector());
+ }
+
+ @VisibleForTesting
+ BlobStoreManagerService(Context context, Injector injector) {
super(context);
+
mContext = context;
+ mInjector = injector;
+ mHandler = mInjector.initializeMessageHandler();
+ }
+ private static Handler initializeMessageHandler() {
final HandlerThread handlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
handlerThread.start();
- mHandler = new Handler(handlerThread.getLooper());
- Watchdog.getInstance().addThread(mHandler);
+ final Handler handler = new Handler(handlerThread.getLooper());
+ Watchdog.getInstance().addThread(handler);
+ return handler;
}
@Override
@@ -181,6 +201,20 @@ public class BlobStoreManagerService extends SystemService {
return userBlobs;
}
+ @VisibleForTesting
+ void addUserSessionsForTest(LongSparseArray<BlobStoreSession> userSessions, int userId) {
+ synchronized (mBlobsLock) {
+ mSessions.put(userId, userSessions);
+ }
+ }
+
+ @VisibleForTesting
+ void addUserBlobsForTest(ArrayMap<BlobHandle, BlobMetadata> userBlobs, int userId) {
+ synchronized (mBlobsLock) {
+ mBlobsMap.put(userId, userBlobs);
+ }
+ }
+
private long createSessionInternal(BlobHandle blobHandle,
int callingUid, String callingPackage) {
synchronized (mBlobsLock) {
@@ -293,23 +327,23 @@ public class BlobStoreManagerService extends SystemService {
case STATE_ABANDONED:
case STATE_VERIFIED_INVALID:
session.getSessionFile().delete();
- getUserSessionsLocked(UserHandle.getUserId(session.ownerUid))
- .remove(session.sessionId);
+ getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid()))
+ .remove(session.getSessionId());
break;
case STATE_COMMITTED:
session.verifyBlobData();
break;
case STATE_VERIFIED_VALID:
- final int userId = UserHandle.getUserId(session.ownerUid);
+ final int userId = UserHandle.getUserId(session.getOwnerUid());
final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(userId);
- BlobMetadata blob = userBlobs.get(session.blobHandle);
+ BlobMetadata blob = userBlobs.get(session.getBlobHandle());
if (blob == null) {
blob = new BlobMetadata(mContext,
- session.sessionId, session.blobHandle, userId);
- userBlobs.put(session.blobHandle, blob);
+ session.getSessionId(), session.getBlobHandle(), userId);
+ userBlobs.put(session.getBlobHandle(), blob);
}
- final Committer newCommitter = new Committer(session.ownerPackageName,
- session.ownerUid, session.getBlobAccessMode());
+ final Committer newCommitter = new Committer(session.getOwnerPackageName(),
+ session.getOwnerUid(), session.getBlobAccessMode());
final Committer existingCommitter = blob.getExistingCommitter(newCommitter);
blob.addCommitter(newCommitter);
try {
@@ -319,8 +353,8 @@ public class BlobStoreManagerService extends SystemService {
blob.addCommitter(existingCommitter);
session.sendCommitCallbackResult(COMMIT_RESULT_ERROR);
}
- getUserSessionsLocked(UserHandle.getUserId(session.ownerUid))
- .remove(session.sessionId);
+ getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid()))
+ .remove(session.getSessionId());
break;
default:
Slog.wtf(TAG, "Invalid session state: "
@@ -399,17 +433,17 @@ public class BlobStoreManagerService extends SystemService {
continue;
}
final SparseArray<String> userPackages = allPackages.get(
- UserHandle.getUserId(session.ownerUid));
+ UserHandle.getUserId(session.getOwnerUid()));
if (userPackages != null
- && session.ownerPackageName.equals(
- userPackages.get(session.ownerUid))) {
- getUserSessionsLocked(UserHandle.getUserId(session.ownerUid)).put(
- session.sessionId, session);
+ && session.getOwnerPackageName().equals(
+ userPackages.get(session.getOwnerUid()))) {
+ getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid())).put(
+ session.getSessionId(), session);
} else {
// Unknown package or the session data does not belong to this package.
session.getSessionFile().delete();
}
- mCurrentMaxSessionId = Math.max(mCurrentMaxSessionId, session.sessionId);
+ mCurrentMaxSessionId = Math.max(mCurrentMaxSessionId, session.getSessionId());
}
}
} catch (Exception e) {
@@ -504,9 +538,9 @@ public class BlobStoreManagerService extends SystemService {
}
private void writeBlobsInfoAsync() {
- mHandler.post(PooledLambda.obtainRunnable(
- BlobStoreManagerService::writeBlobsInfo,
- BlobStoreManagerService.this).recycleOnUse());
+ if (!mHandler.hasCallbacks(mSaveBlobsInfoRunnable)) {
+ mHandler.post(mSaveBlobsInfoRunnable);
+ }
}
private void writeBlobSessions() {
@@ -520,9 +554,9 @@ public class BlobStoreManagerService extends SystemService {
}
private void writeBlobSessionsAsync() {
- mHandler.post(PooledLambda.obtainRunnable(
- BlobStoreManagerService::writeBlobSessions,
- BlobStoreManagerService.this).recycleOnUse());
+ if (!mHandler.hasCallbacks(mSaveSessionsRunnable)) {
+ mHandler.post(mSaveSessionsRunnable);
+ }
}
private int getPackageUid(String packageName, int userId) {
@@ -568,7 +602,8 @@ public class BlobStoreManagerService extends SystemService {
return new AtomicFile(file, "blobs_index" /* commitLogTag */);
}
- private void handlePackageRemoved(String packageName, int uid) {
+ @VisibleForTesting
+ void handlePackageRemoved(String packageName, int uid) {
synchronized (mBlobsLock) {
// Clean up any pending sessions
final LongSparseArray<BlobStoreSession> userSessions =
@@ -576,25 +611,35 @@ public class BlobStoreManagerService extends SystemService {
final ArrayList<Integer> indicesToRemove = new ArrayList<>();
for (int i = 0, count = userSessions.size(); i < count; ++i) {
final BlobStoreSession session = userSessions.valueAt(i);
- if (session.ownerUid == uid
- && session.ownerPackageName.equals(packageName)) {
+ if (session.getOwnerUid() == uid
+ && session.getOwnerPackageName().equals(packageName)) {
session.getSessionFile().delete();
indicesToRemove.add(i);
}
}
for (int i = 0, count = indicesToRemove.size(); i < count; ++i) {
- userSessions.removeAt(i);
+ userSessions.removeAt(indicesToRemove.get(i));
}
+ writeBlobSessionsAsync();
// Remove the package from the committer and leasee list
final ArrayMap<BlobHandle, BlobMetadata> userBlobs =
getUserBlobsLocked(UserHandle.getUserId(uid));
+ indicesToRemove.clear();
for (int i = 0, count = userBlobs.size(); i < count; ++i) {
final BlobMetadata blobMetadata = userBlobs.valueAt(i);
blobMetadata.removeCommitter(packageName, uid);
blobMetadata.removeLeasee(packageName, uid);
+ // Delete the blob if it doesn't have any active leases.
+ if (!blobMetadata.hasLeases()) {
+ blobMetadata.getBlobFile().delete();
+ indicesToRemove.add(i);
+ }
+ }
+ for (int i = 0, count = indicesToRemove.size(); i < count; ++i) {
+ userBlobs.removeAt(indicesToRemove.get(i));
}
- // TODO: clean-up blobs which doesn't have any active leases.
+ writeBlobsInfoAsync();
}
}
@@ -620,6 +665,80 @@ public class BlobStoreManagerService extends SystemService {
}
}
+ void runClearAllSessions(@UserIdInt int userId) {
+ synchronized (mBlobsLock) {
+ if (userId == UserHandle.USER_ALL) {
+ mSessions.clear();
+ } else {
+ mSessions.remove(userId);
+ }
+ writeBlobSessionsAsync();
+ }
+ }
+
+ void runClearAllBlobs(@UserIdInt int userId) {
+ synchronized (mBlobsLock) {
+ if (userId == UserHandle.USER_ALL) {
+ mBlobsMap.clear();
+ } else {
+ mBlobsMap.remove(userId);
+ }
+ writeBlobsInfoAsync();
+ }
+ }
+
+ @GuardedBy("mBlobsLock")
+ private void dumpSessionsLocked(IndentingPrintWriter fout, DumpArgs dumpArgs) {
+ for (int i = 0, userCount = mSessions.size(); i < userCount; ++i) {
+ final int userId = mSessions.keyAt(i);
+ if (!dumpArgs.shouldDumpUser(userId)) {
+ continue;
+ }
+ final LongSparseArray<BlobStoreSession> userSessions = mSessions.valueAt(i);
+ fout.println("List of sessions in user #"
+ + userId + " (" + userSessions.size() + "):");
+ fout.increaseIndent();
+ for (int j = 0, sessionsCount = userSessions.size(); j < sessionsCount; ++j) {
+ final long sessionId = userSessions.keyAt(j);
+ final BlobStoreSession session = userSessions.valueAt(j);
+ if (!dumpArgs.shouldDumpSession(session.getOwnerPackageName(),
+ session.getOwnerUid(), session.getSessionId())) {
+ continue;
+ }
+ fout.println("Session #" + sessionId);
+ fout.increaseIndent();
+ session.dump(fout, dumpArgs);
+ fout.decreaseIndent();
+ }
+ fout.decreaseIndent();
+ }
+ }
+
+ @GuardedBy("mBlobsLock")
+ private void dumpBlobsLocked(IndentingPrintWriter fout, DumpArgs dumpArgs) {
+ for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
+ final int userId = mBlobsMap.keyAt(i);
+ if (!dumpArgs.shouldDumpUser(userId)) {
+ continue;
+ }
+ final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
+ fout.println("List of blobs in user #"
+ + userId + " (" + userBlobs.size() + "):");
+ fout.increaseIndent();
+ for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) {
+ final BlobMetadata blobMetadata = userBlobs.valueAt(j);
+ if (!dumpArgs.shouldDumpBlob(blobMetadata.blobId)) {
+ continue;
+ }
+ fout.println("Blob #" + blobMetadata.blobId);
+ fout.increaseIndent();
+ blobMetadata.dump(fout, dumpArgs);
+ fout.decreaseIndent();
+ }
+ fout.decreaseIndent();
+ }
+ }
+
private class PackageChangedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
@@ -658,10 +777,9 @@ public class BlobStoreManagerService extends SystemService {
@IntRange(from = 1)
public long createSession(@NonNull BlobHandle blobHandle,
@NonNull String packageName) {
- Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
- Preconditions.checkNotNull(packageName, "packageName must not be null");
- // TODO: verify blobHandle.algorithm is sha-256
- // TODO: assert blobHandle is valid.
+ Objects.requireNonNull(blobHandle, "blobHandle must not be null");
+ blobHandle.assertIsValid();
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
@@ -682,7 +800,7 @@ public class BlobStoreManagerService extends SystemService {
@NonNull String packageName) {
Preconditions.checkArgumentPositive(sessionId,
"sessionId must be positive: " + sessionId);
- Preconditions.checkNotNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
@@ -695,7 +813,7 @@ public class BlobStoreManagerService extends SystemService {
@NonNull String packageName) {
Preconditions.checkArgumentPositive(sessionId,
"sessionId must be positive: " + sessionId);
- Preconditions.checkNotNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
@@ -706,8 +824,9 @@ public class BlobStoreManagerService extends SystemService {
@Override
public ParcelFileDescriptor openBlob(@NonNull BlobHandle blobHandle,
@NonNull String packageName) {
- Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
- Preconditions.checkNotNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(blobHandle, "blobHandle must not be null");
+ blobHandle.assertIsValid();
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
@@ -727,24 +846,27 @@ public class BlobStoreManagerService extends SystemService {
@Override
public void acquireLease(@NonNull BlobHandle blobHandle, @IdRes int descriptionResId,
- @CurrentTimeSecondsLong long leaseTimeoutSecs, @NonNull String packageName) {
- Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
- Preconditions.checkNotNull(packageName, "packageName must not be null");
- Preconditions.checkArgumentPositive(descriptionResId,
- "descriptionResId must be positive; value=" + descriptionResId);
+ @CurrentTimeSecondsLong long leaseExpiryTimeMillis, @NonNull String packageName) {
+ Objects.requireNonNull(blobHandle, "blobHandle must not be null");
+ blobHandle.assertIsValid();
+ Preconditions.checkArgument(ResourceId.isValid(descriptionResId),
+ "descriptionResId is not valid");
+ Preconditions.checkArgumentNonnegative(leaseExpiryTimeMillis,
+ "leaseExpiryTimeMillis must not be negative");
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
- acquireLeaseInternal(blobHandle, descriptionResId, leaseTimeoutSecs,
+ acquireLeaseInternal(blobHandle, descriptionResId, leaseExpiryTimeMillis,
callingUid, packageName);
}
@Override
public void releaseLease(@NonNull BlobHandle blobHandle, @NonNull String packageName) {
- Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
- Preconditions.checkNotNull(packageName, "packageName must not be null");
-
+ Objects.requireNonNull(blobHandle, "blobHandle must not be null");
+ blobHandle.assertIsValid();
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
@@ -754,7 +876,7 @@ public class BlobStoreManagerService extends SystemService {
@Override
public void waitForIdle(@NonNull RemoteCallback remoteCallback) {
- Preconditions.checkNotNull(remoteCallback, "remoteCallback must not be null");
+ Objects.requireNonNull(remoteCallback, "remoteCallback must not be null");
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
"Caller is not allowed to call this; caller=" + Binder.getCallingUid());
@@ -766,47 +888,164 @@ public class BlobStoreManagerService extends SystemService {
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
@Nullable String[] args) {
// TODO: add proto-based version of this.
- if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, writer)) return;
+
+ final DumpArgs dumpArgs = DumpArgs.parse(args);
final IndentingPrintWriter fout = new IndentingPrintWriter(writer, " ");
synchronized (mBlobsLock) {
fout.println("mCurrentMaxSessionId: " + mCurrentMaxSessionId);
fout.println();
- for (int i = 0, userCount = mSessions.size(); i < userCount; ++i) {
- final int userId = mSessions.keyAt(i);
- final LongSparseArray<BlobStoreSession> userSessions = mSessions.valueAt(i);
- fout.println("List of sessions in user #"
- + userId + " (" + userSessions.size() + "):");
- fout.increaseIndent();
- for (int j = 0, sessionsCount = userSessions.size(); j < sessionsCount; ++j) {
- final long sessionId = userSessions.keyAt(j);
- final BlobStoreSession session = userSessions.valueAt(j);
- fout.println("Session #" + sessionId);
- fout.increaseIndent();
- session.dump(fout);
- fout.decreaseIndent();
- }
- fout.decreaseIndent();
+
+ if (dumpArgs.shouldDumpSessions()) {
+ dumpSessionsLocked(fout, dumpArgs);
+ fout.println();
+ }
+ if (dumpArgs.shouldDumpBlobs()) {
+ dumpBlobsLocked(fout, dumpArgs);
+ fout.println();
}
+ }
+ }
+
+ @Override
+ public int handleShellCommand(@NonNull ParcelFileDescriptor in,
+ @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
+ @NonNull String[] args) {
+ return (new BlobStoreManagerShellCommand(BlobStoreManagerService.this)).exec(this,
+ in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), args);
+ }
+ }
+
+ static final class DumpArgs {
+ private boolean mDumpFull;
+ private final ArrayList<String> mDumpPackages = new ArrayList<>();
+ private final ArrayList<Integer> mDumpUids = new ArrayList<>();
+ private final ArrayList<Integer> mDumpUserIds = new ArrayList<>();
+ private final ArrayList<Long> mDumpBlobIds = new ArrayList<>();
+ private boolean mDumpOnlySelectedSections;
+ private boolean mDumpSessions;
+ private boolean mDumpBlobs;
+
+ public boolean shouldDumpSession(String packageName, int uid, long blobId) {
+ if (!CollectionUtils.isEmpty(mDumpPackages)
+ && mDumpPackages.indexOf(packageName) < 0) {
+ return false;
+ }
+ if (!CollectionUtils.isEmpty(mDumpUids)
+ && mDumpUids.indexOf(uid) < 0) {
+ return false;
+ }
+ if (!CollectionUtils.isEmpty(mDumpBlobIds)
+ && mDumpBlobIds.indexOf(blobId) < 0) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean shouldDumpSessions() {
+ if (!mDumpOnlySelectedSections) {
+ return true;
+ }
+ return mDumpSessions;
+ }
+
+ public boolean shouldDumpBlobs() {
+ if (!mDumpOnlySelectedSections) {
+ return true;
+ }
+ return mDumpBlobs;
+ }
+
+ public boolean shouldDumpBlob(long blobId) {
+ return CollectionUtils.isEmpty(mDumpBlobIds)
+ || mDumpBlobIds.indexOf(blobId) >= 0;
+ }
+
+ public boolean shouldDumpFull() {
+ return mDumpFull;
+ }
+
+ public boolean shouldDumpUser(int userId) {
+ return CollectionUtils.isEmpty(mDumpUserIds)
+ || mDumpUserIds.indexOf(userId) >= 0;
+ }
+
+ private DumpArgs() {}
- fout.print("\n\n");
-
- for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
- final int userId = mBlobsMap.keyAt(i);
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
- fout.println("List of blobs in user #"
- + userId + " (" + userBlobs.size() + "):");
- fout.increaseIndent();
- for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) {
- final BlobMetadata blobMetadata = userBlobs.valueAt(j);
- fout.println("Blob #" + blobMetadata.blobId);
- fout.increaseIndent();
- blobMetadata.dump(fout);
- fout.decreaseIndent();
+ public static DumpArgs parse(String[] args) {
+ final DumpArgs dumpArgs = new DumpArgs();
+ if (args == null) {
+ return dumpArgs;
+ }
+
+ for (int i = 0; i < args.length; ++i) {
+ final String opt = args[i];
+ if ("--full".equals(opt) || "-f".equals(opt)) {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
+ dumpArgs.mDumpFull = true;
}
- fout.decreaseIndent();
+ } else if ("--sessions".equals(opt)) {
+ dumpArgs.mDumpOnlySelectedSections = true;
+ dumpArgs.mDumpSessions = true;
+ } else if ("--blobs".equals(opt)) {
+ dumpArgs.mDumpOnlySelectedSections = true;
+ dumpArgs.mDumpBlobs = true;
+ } else if ("--package".equals(opt) || "-p".equals(opt)) {
+ dumpArgs.mDumpPackages.add(getStringArgRequired(args, ++i, "packageName"));
+ } else if ("--uid".equals(opt) || "-u".equals(opt)) {
+ dumpArgs.mDumpUids.add(getIntArgRequired(args, ++i, "uid"));
+ } else if ("--user".equals(opt)) {
+ dumpArgs.mDumpUserIds.add(getIntArgRequired(args, ++i, "userId"));
+ } else if ("--blob".equals(opt) || "-b".equals(opt)) {
+ dumpArgs.mDumpBlobIds.add(getLongArgRequired(args, ++i, "blobId"));
+ } else {
+ // Everything else is assumed to be blob ids.
+ dumpArgs.mDumpBlobIds.add(getLongArgRequired(args, i, "blobId"));
}
}
+ return dumpArgs;
+ }
+
+ private static String getStringArgRequired(String[] args, int index, String argName) {
+ if (index >= args.length) {
+ throw new IllegalArgumentException("Missing " + argName);
+ }
+ return args[index];
+ }
+
+ private static int getIntArgRequired(String[] args, int index, String argName) {
+ if (index >= args.length) {
+ throw new IllegalArgumentException("Missing " + argName);
+ }
+ final int value;
+ try {
+ value = Integer.parseInt(args[index]);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid " + argName + ": " + args[index]);
+ }
+ return value;
+ }
+
+ private static long getLongArgRequired(String[] args, int index, String argName) {
+ if (index >= args.length) {
+ throw new IllegalArgumentException("Missing " + argName);
+ }
+ final long value;
+ try {
+ value = Long.parseLong(args[index]);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid " + argName + ": " + args[index]);
+ }
+ return value;
+ }
+ }
+
+ @VisibleForTesting
+ static class Injector {
+ public Handler initializeMessageHandler() {
+ return BlobStoreManagerService.initializeMessageHandler();
}
}
} \ No newline at end of file
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java
new file mode 100644
index 000000000000..3ac30f8fff6c
--- /dev/null
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2020 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.blob;
+
+import android.os.ShellCommand;
+import android.os.UserHandle;
+
+import java.io.PrintWriter;
+
+class BlobStoreManagerShellCommand extends ShellCommand {
+
+ private final BlobStoreManagerService mService;
+
+ BlobStoreManagerShellCommand(BlobStoreManagerService blobStoreManagerService) {
+ mService = blobStoreManagerService;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(null);
+ }
+ final PrintWriter pw = getOutPrintWriter();
+ switch (cmd) {
+ case "clear-all-sessions":
+ return runClearAllSessions(pw);
+ case "clear-all-blobs":
+ return runClearAllBlobs(pw);
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ }
+
+ private int runClearAllSessions(PrintWriter pw) {
+ final ParsedArgs args = new ParsedArgs();
+ args.userId = UserHandle.USER_ALL;
+
+ if (parseOptions(pw, args) < 0) {
+ return -1;
+ }
+
+ mService.runClearAllSessions(args.userId);
+ return 0;
+ }
+
+ private int runClearAllBlobs(PrintWriter pw) {
+ final ParsedArgs args = new ParsedArgs();
+ args.userId = UserHandle.USER_ALL;
+
+ if (parseOptions(pw, args) < 0) {
+ return -1;
+ }
+
+ mService.runClearAllBlobs(args.userId);
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ final PrintWriter pw = getOutPrintWriter();
+ pw.println("BlobStore service (blob_store) commands:");
+ pw.println("help");
+ pw.println(" Print this help text.");
+ pw.println();
+ pw.println("clear-all-sessions [-u | --user USER_ID]");
+ pw.println(" Remove all sessions.");
+ pw.println(" Options:");
+ pw.println(" -u or --user: specify which user's sessions to be removed;");
+ pw.println(" If not specified, sessions in all users are removed.");
+ pw.println();
+ pw.println("clear-all-blobs [-u | --user USER_ID]");
+ pw.println(" Remove all blobs.");
+ pw.println(" Options:");
+ pw.println(" -u or --user: specify which user's blobs to be removed;");
+ pw.println(" If not specified, blobs in all users are removed.");
+ pw.println();
+ }
+
+ private int parseOptions(PrintWriter pw, ParsedArgs args) {
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "-u":
+ case "--user":
+ args.userId = Integer.parseInt(getNextArgRequired());
+ break;
+ default:
+ pw.println("Error: unknown option '" + opt + "'");
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ private static class ParsedArgs {
+ public int userId;
+ }
+}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
index 7d1c16653383..54a299722754 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
@@ -47,9 +47,11 @@ import android.util.ExceptionUtils;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
+import com.android.server.blob.BlobStoreManagerService.DumpArgs;
import com.android.server.blob.BlobStoreManagerService.SessionStateChangeListener;
import org.xmlpull.v1.XmlPullParser;
@@ -62,9 +64,11 @@ import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Objects;
/** TODO: add doc */
-public class BlobStoreSession extends IBlobStoreSession.Stub {
+@VisibleForTesting
+class BlobStoreSession extends IBlobStoreSession.Stub {
static final int STATE_OPENED = 1;
static final int STATE_CLOSED = 0;
@@ -78,10 +82,10 @@ public class BlobStoreSession extends IBlobStoreSession.Stub {
private final Context mContext;
private final SessionStateChangeListener mListener;
- public final BlobHandle blobHandle;
- public final long sessionId;
- public final int ownerUid;
- public final String ownerPackageName;
+ private final BlobHandle mBlobHandle;
+ private final long mSessionId;
+ private final int mOwnerUid;
+ private final String mOwnerPackageName;
// Do not access this directly, instead use getSessionFile().
private File mSessionFile;
@@ -101,15 +105,31 @@ public class BlobStoreSession extends IBlobStoreSession.Stub {
BlobStoreSession(Context context, long sessionId, BlobHandle blobHandle,
int ownerUid, String ownerPackageName, SessionStateChangeListener listener) {
this.mContext = context;
- this.blobHandle = blobHandle;
- this.sessionId = sessionId;
- this.ownerUid = ownerUid;
- this.ownerPackageName = ownerPackageName;
+ this.mBlobHandle = blobHandle;
+ this.mSessionId = sessionId;
+ this.mOwnerUid = ownerUid;
+ this.mOwnerPackageName = ownerPackageName;
this.mListener = listener;
}
+ public BlobHandle getBlobHandle() {
+ return mBlobHandle;
+ }
+
+ public long getSessionId() {
+ return mSessionId;
+ }
+
+ public int getOwnerUid() {
+ return mOwnerUid;
+ }
+
+ public String getOwnerPackageName() {
+ return mOwnerPackageName;
+ }
+
boolean hasAccess(int callingUid, String callingPackageName) {
- return ownerUid == callingUid && ownerPackageName.equals(callingPackageName);
+ return mOwnerUid == callingUid && mOwnerPackageName.equals(callingPackageName);
}
void open() {
@@ -155,6 +175,8 @@ public class BlobStoreSession extends IBlobStoreSession.Stub {
@NonNull
public ParcelFileDescriptor openWrite(@BytesLong long offsetBytes,
@BytesLong long lengthBytes) {
+ Preconditions.checkArgumentNonnegative(offsetBytes, "offsetBytes must not be negative");
+
assertCallerIsOwner();
synchronized (mSessionLock) {
if (mState != STATE_OPENED) {
@@ -242,7 +264,7 @@ public class BlobStoreSession extends IBlobStoreSession.Stub {
public void allowPackageAccess(@NonNull String packageName,
@NonNull byte[] certificate) {
assertCallerIsOwner();
- Preconditions.checkNotNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(packageName, "packageName must not be null");
synchronized (mSessionLock) {
if (mState != STATE_OPENED) {
throw new IllegalStateException("Not allowed to change access type in state: "
@@ -280,7 +302,9 @@ public class BlobStoreSession extends IBlobStoreSession.Stub {
public boolean isPackageAccessAllowed(@NonNull String packageName,
@NonNull byte[] certificate) {
assertCallerIsOwner();
- Preconditions.checkNotNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(packageName, "packageName must not be null");
+ Preconditions.checkByteArrayNotEmpty(certificate, "certificate");
+
synchronized (mSessionLock) {
if (mState != STATE_OPENED) {
throw new IllegalStateException("Not allowed to get access type in state: "
@@ -357,12 +381,12 @@ public class BlobStoreSession extends IBlobStoreSession.Stub {
void verifyBlobData() {
byte[] actualDigest = null;
try {
- actualDigest = FileUtils.digest(getSessionFile(), blobHandle.algorithm);
+ actualDigest = FileUtils.digest(getSessionFile(), mBlobHandle.algorithm);
} catch (IOException | NoSuchAlgorithmException e) {
Slog.e(TAG, "Error computing the digest", e);
}
synchronized (mSessionLock) {
- if (actualDigest != null && Arrays.equals(actualDigest, blobHandle.digest)) {
+ if (actualDigest != null && Arrays.equals(actualDigest, mBlobHandle.digest)) {
mState = STATE_VERIFIED_VALID;
// Commit callback will be sent once the data is persisted.
} else {
@@ -401,7 +425,7 @@ public class BlobStoreSession extends IBlobStoreSession.Stub {
@Nullable
File getSessionFile() {
if (mSessionFile == null) {
- mSessionFile = BlobStoreConfig.prepareBlobFile(sessionId);
+ mSessionFile = BlobStoreConfig.prepareBlobFile(mSessionId);
}
return mSessionFile;
}
@@ -425,20 +449,20 @@ public class BlobStoreSession extends IBlobStoreSession.Stub {
private void assertCallerIsOwner() {
final int callingUid = Binder.getCallingUid();
- if (callingUid != ownerUid) {
- throw new SecurityException(ownerUid + " is not the session owner");
+ if (callingUid != mOwnerUid) {
+ throw new SecurityException(mOwnerUid + " is not the session owner");
}
}
- void dump(IndentingPrintWriter fout) {
+ void dump(IndentingPrintWriter fout, DumpArgs dumpArgs) {
synchronized (mSessionLock) {
fout.println("state: " + stateToString(mState));
- fout.println("ownerUid: " + ownerUid);
- fout.println("ownerPkg: " + ownerPackageName);
+ fout.println("ownerUid: " + mOwnerUid);
+ fout.println("ownerPkg: " + mOwnerPackageName);
fout.println("blobHandle:");
fout.increaseIndent();
- blobHandle.dump(fout);
+ mBlobHandle.dump(fout, dumpArgs.shouldDumpFull());
fout.decreaseIndent();
fout.println("accessMode:");
@@ -452,12 +476,12 @@ public class BlobStoreSession extends IBlobStoreSession.Stub {
void writeToXml(@NonNull XmlSerializer out) throws IOException {
synchronized (mSessionLock) {
- XmlUtils.writeLongAttribute(out, ATTR_ID, sessionId);
- XmlUtils.writeStringAttribute(out, ATTR_PACKAGE, ownerPackageName);
- XmlUtils.writeIntAttribute(out, ATTR_UID, ownerUid);
+ XmlUtils.writeLongAttribute(out, ATTR_ID, mSessionId);
+ XmlUtils.writeStringAttribute(out, ATTR_PACKAGE, mOwnerPackageName);
+ XmlUtils.writeIntAttribute(out, ATTR_UID, mOwnerUid);
out.startTag(null, TAG_BLOB_HANDLE);
- blobHandle.writeToXml(out);
+ mBlobHandle.writeToXml(out);
out.endTag(null, TAG_BLOB_HANDLE);
out.startTag(null, TAG_ACCESS_MODE);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index ed5626a1acbc..69f4748548a7 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -77,7 +77,6 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
-import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -85,6 +84,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.AppStateTracker;
import com.android.server.DeviceIdleInternal;
@@ -1171,9 +1171,9 @@ public class JobSchedulerService extends com.android.server.SystemService
jobStatus.enqueueWorkLocked(work);
}
- StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_STATE_CHANGED,
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
uId, null, jobStatus.getBatteryName(),
- StatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__SCHEDULED,
+ FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__SCHEDULED,
JobProtoEnums.STOP_REASON_CANCELLED, jobStatus.getStandbyBucket(),
jobStatus.getJobId());
@@ -2567,7 +2567,8 @@ public class JobSchedulerService extends com.android.server.SystemService
BatteryStatsInternal mBatteryStatsInternal = LocalServices.getService
(BatteryStatsInternal.class);
mBatteryStatsInternal.noteJobsDeferred(uid, counter.numDeferred(), sinceLast);
- StatsLog.write_non_chained(StatsLog.DEFERRED_JOB_STATS_REPORTED, uid, null,
+ FrameworkStatsLog.write_non_chained(
+ FrameworkStatsLog.DEFERRED_JOB_STATS_REPORTED, uid, null,
counter.numDeferred(), sinceLast);
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index dbdce70dda03..f706260edec2 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -32,10 +32,10 @@ import android.text.format.DateFormat;
import android.util.ArraySet;
import android.util.Pair;
import android.util.Slog;
-import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.job.GrantedUriPermissions;
import com.android.server.job.JobSchedulerInternal;
@@ -1059,10 +1059,12 @@ public final class JobStatus {
mReadyDynamicSatisfied =
mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
if (STATS_LOG_ENABLED && (STATSD_CONSTRAINTS_TO_LOG & constraint) != 0) {
- StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED,
+ FrameworkStatsLog.write_non_chained(
+ FrameworkStatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED,
sourceUid, null, getBatteryName(), getProtoConstraint(constraint),
- state ? StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED
- : StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED);
+ state ? FrameworkStatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED
+ : FrameworkStatsLog
+ .SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED);
}
return true;
}
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 2266d049d70a..91df09865037 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -99,13 +99,10 @@ filegroup {
path: "java"
}
-droidstubs {
- name: "updatable-media-stubs",
- srcs: [
- ":updatable-media-srcs",
- ":framework-media-annotation-srcs",
- ],
- defaults: [ "framework-module-stubs-defaults-systemapi" ],
+stubs_defaults {
+ name: "framework-media-stubs-srcs-defaults",
+ srcs: [ ":updatable-media-srcs" ],
+ libs: [ "framework_media_annotation" ],
aidl: {
// TODO(b/135922046) remove this
include_dirs: ["frameworks/base/core/java"],
@@ -113,9 +110,53 @@ droidstubs {
sdk_version: "system_current",
}
+droidstubs {
+ name: "framework-media-stubs-srcs-publicapi",
+ defaults: [
+ "framework-media-stubs-srcs-defaults",
+ "framework-module-stubs-defaults-publicapi",
+ ],
+}
+
+droidstubs {
+ name: "framework-media-stubs-srcs-systemapi",
+ defaults: [
+ "framework-media-stubs-srcs-defaults",
+ "framework-module-stubs-defaults-systemapi",
+ ],
+}
+
+droidstubs {
+ name: "framework-media-api-module_libs_api",
+ defaults: [
+ "framework-media-stubs-srcs-defaults",
+ "framework-module-api-defaults-module_libs_api",
+ ],
+}
+
+droidstubs {
+ name: "framework-media-stubs-srcs-module_libs_api",
+ defaults: [
+ "framework-media-stubs-srcs-defaults",
+ "framework-module-stubs-defaults-module_libs_api",
+ ],
+}
+
+java_library {
+ name: "framework-media-stubs-publicapi",
+ srcs: [":framework-media-stubs-srcs-publicapi"],
+ sdk_version: "current",
+}
+
+java_library {
+ name: "framework-media-stubs-systemapi",
+ srcs: [":framework-media-stubs-srcs-systemapi"],
+ sdk_version: "system_current",
+}
+
java_library {
- name: "updatable_media_stubs",
- srcs: [":updatable-media-stubs"],
+ name: "framework-media-stubs-module_libs_api",
+ srcs: [":framework-media-stubs-srcs-module_libs_api"],
sdk_version: "system_current",
}
diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp
index 09571a1cd111..126fa00a31f0 100644
--- a/apex/permission/framework/Android.bp
+++ b/apex/permission/framework/Android.bp
@@ -44,23 +44,66 @@ java_library {
],
}
+stubs_defaults {
+ name: "framework-permission-stubs-defaults",
+ srcs: [ ":framework-permission-sources" ],
+ libs: [ "framework-annotations-lib" ],
+ sdk_version: "system_current",
+}
+
droidstubs {
- name: "framework-permission-stubs-sources",
- srcs: [
- ":framework-annotations",
- ":framework-permission-sources",
+ name: "framework-permission-stubs-srcs-publicapi",
+ sdk_version: "system_current",
+ defaults: [
+ "framework-module-stubs-defaults-publicapi",
+ "framework-permission-stubs-defaults",
],
+}
+
+droidstubs {
+ name: "framework-permission-stubs-srcs-systemapi",
sdk_version: "system_current",
defaults: [
"framework-module-stubs-defaults-systemapi",
+ "framework-permission-stubs-defaults",
],
}
-java_library {
- name: "framework-permission-stubs",
- srcs: [
- ":framework-permission-stubs-sources",
+droidstubs {
+ name: "framework-permission-api-module_libs_api",
+ sdk_version: "system_current",
+ defaults: [
+ "framework-module-api-defaults-module_libs_api",
+ "framework-permission-stubs-defaults",
+ ],
+}
+
+droidstubs {
+ name: "framework-permission-stubs-srcs-module_libs_api",
+ sdk_version: "system_current",
+ defaults: [
+ "framework-module-stubs-defaults-module_libs_api",
+ "framework-permission-stubs-defaults",
],
+}
+
+java_library {
+ name: "framework-permission-stubs-publicapi",
+ srcs: [ ":framework-permission-stubs-srcs-publicapi" ],
+ sdk_version: "system_current",
+ installable: false,
+}
+
+java_library {
+ name: "framework-permission-stubs-systemapi",
+ srcs: [ ":framework-permission-stubs-srcs-systemapi" ],
+ sdk_version: "system_current",
+ installable: false,
+}
+
+java_library {
+ name: "framework-permission-stubs-module_libs_api",
+ srcs: [ ":framework-permission-stubs-srcs-module_libs_api" ],
sdk_version: "system_current",
installable: false,
}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
index 5f2d94441965..6c7f82a11908 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
@@ -19,6 +19,7 @@ package com.android.permission.persistence;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.SystemApi.Client;
import android.os.UserHandle;
/**
@@ -27,7 +28,7 @@ import android.os.UserHandle;
* TODO(b/147914847): Remove @hide when it becomes the default.
* @hide
*/
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES, process = SystemApi.Process.SYSTEM_SERVER)
+@SystemApi(client = Client.SYSTEM_SERVER)
public interface RuntimePermissionsPersistence {
/**
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
index 2a939e51b98e..cd2750a0bee5 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
@@ -19,6 +19,7 @@ package com.android.permission.persistence;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.SystemApi.Client;
import java.util.List;
import java.util.Map;
@@ -29,7 +30,7 @@ import java.util.Map;
* TODO(b/147914847): Remove @hide when it becomes the default.
* @hide
*/
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES, process = SystemApi.Process.SYSTEM_SERVER)
+@SystemApi(client = Client.SYSTEM_SERVER)
public final class RuntimePermissionsState {
/**
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
index 63c8eedd6285..2908a3872df9 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
@@ -19,6 +19,7 @@ package com.android.role.persistence;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.SystemApi.Client;
import android.os.UserHandle;
/**
@@ -27,7 +28,7 @@ import android.os.UserHandle;
* TODO(b/147914847): Remove @hide when it becomes the default.
* @hide
*/
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES, process = SystemApi.Process.SYSTEM_SERVER)
+@SystemApi(client = Client.SYSTEM_SERVER)
public interface RolesPersistence {
/**
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesState.java b/apex/permission/service/java/com/android/role/persistence/RolesState.java
index bff980e2e126..7da9d11f172f 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesState.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesState.java
@@ -19,6 +19,7 @@ package com.android.role.persistence;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.SystemApi.Client;
import java.util.Map;
import java.util.Set;
@@ -29,7 +30,7 @@ import java.util.Set;
* TODO(b/147914847): Remove @hide when it becomes the default.
* @hide
*/
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES, process = SystemApi.Process.SYSTEM_SERVER)
+@SystemApi(client = Client.SYSTEM_SERVER)
public final class RolesState {
/**
diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp
index 245a96b99148..86f4ab7c1128 100644
--- a/apex/sdkextensions/framework/Android.bp
+++ b/apex/sdkextensions/framework/Android.bp
@@ -44,34 +44,68 @@ java_library {
],
}
+stubs_defaults {
+ name: "framework-sdkextensions-stubs-defaults",
+ srcs: [ ":framework-sdkextensions-sources" ],
+ libs: [ "framework-annotations-lib" ],
+ sdk_version: "system_current",
+}
+
droidstubs {
- name: "framework-sdkextensions-droidstubs-publicapi",
+ name: "framework-sdkextensions-stubs-srcs-publicapi",
defaults: [
- "framework-sdkextensions-stubs-defaults",
"framework-module-stubs-defaults-publicapi",
+ "framework-sdkextensions-stubs-defaults",
]
}
droidstubs {
- name: "framework-sdkextensions-droidstubs-systemapi",
+ name: "framework-sdkextensions-stubs-srcs-systemapi",
defaults: [
- "framework-sdkextensions-stubs-defaults",
"framework-module-stubs-defaults-systemapi",
+ "framework-sdkextensions-stubs-defaults",
]
}
-stubs_defaults {
- name: "framework-sdkextensions-stubs-defaults",
- srcs: [
- ":framework-sdkextensions-sources",
- ":framework-annotations",
- ],
- sdk_version: "system_current",
+droidstubs {
+ name: "framework-sdkextensions-api-module_libs_api",
+ defaults: [
+ "framework-module-api-defaults-module_libs_api",
+ "framework-sdkextensions-stubs-defaults",
+ ]
+}
+
+droidstubs {
+ name: "framework-sdkextensions-stubs-srcs-module_libs_api",
+ defaults: [
+ "framework-module-stubs-defaults-module_libs_api",
+ "framework-sdkextensions-stubs-defaults",
+ ]
+}
+
+java_library {
+ name: "framework-sdkextensions-stubs-publicapi",
+ srcs: [":framework-sdkextensions-stubs-srcs-publicapi"],
+ sdk_version: "current",
+ visibility: [
+ "//frameworks/base", // Framework
+ "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
+ ]
}
java_library {
name: "framework-sdkextensions-stubs-systemapi",
- srcs: [":framework-sdkextensions-droidstubs-systemapi"],
+ srcs: [":framework-sdkextensions-stubs-srcs-systemapi"],
+ sdk_version: "system_current",
+ visibility: [
+ "//frameworks/base", // Framework
+ "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
+ ]
+}
+
+java_library {
+ name: "framework-sdkextensions-stubs-module_libs_api",
+ srcs: [":framework-sdkextensions-stubs-srcs-module_libs_api"],
sdk_version: "system_current",
visibility: [
"//frameworks/base", // Framework
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
index 09ca1d257460..1f9f18cd051a 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -19,8 +19,9 @@ apex {
}
apex_defaults {
- // libc.so and libcutils.so are included in the apex
- // native_shared_libs: ["libc", "libcutils"],
+ native_shared_libs: [
+ "libstats_jni",
+ ],
// binaries: ["vold"],
java_libs: [
"framework-statsd",
@@ -44,3 +45,33 @@ android_app_certificate {
// com.android.os.statsd.pk8 (the private key)
certificate: "com.android.os.statsd",
}
+
+
+// JNI library for StatsLog.write
+cc_library_shared {
+ name: "libstats_jni",
+ srcs: ["jni/**/*.cpp"],
+ shared_libs: [
+ "libnativehelper", // Has stable abi - should not be copied into apex.
+ "liblog", // Has a stable abi - should not be copied into apex.
+ ],
+ static_libs: [
+ //TODO: make shared - need libstatssocket to also live in the apex.
+ "libstatssocket",
+ "libcutils", // TODO: remove - needed by libstatssocket
+ ],
+ //TODO: is libc++_static correct?
+ stl: "libc++_static",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wno-unused-parameter",
+ ],
+ apex_available: [
+ "com.android.os.statsd",
+ "test_com.android.os.statsd",
+ //TODO (b/148620413): remove platform.
+ "//apex_available:platform",
+ ],
+} \ No newline at end of file
diff --git a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
index bdd1da7bf3d3..b94928f09ae0 100644
--- a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
+++ b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
@@ -61,4 +61,11 @@ interface IStatsCompanionService {
/** Tells StatsCompaionService to grab the uid map snapshot and send it to statsd. */
oneway void triggerUidSnapshot();
+
+ /**
+ * Ask StatsCompanionService if the given permission is allowed for a particular process
+ * and user ID. statsd is incapable of doing this check itself because checkCallingPermission
+ * is not currently supported by libbinder_ndk.
+ */
+ boolean checkPermission(String permission, int pid, int uid);
}
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index f66f0340edab..d85ae69b799f 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -30,13 +30,13 @@ java_library {
],
permitted_packages: [
"android.app",
+ "android.os",
"android.util",
],
libs: [
"framework-annotations-lib",
- // TODO(b/146230220): Use framework-system-stubs instead.
- //"android_system_stubs_current",
- //"framework_module_lib_stubs_current",
+ // TODO(b/146230220): Use android_module_lib_stubs_current instead.
+ //"android_module_lib_stubs_current",
"framework-all",
],
hostdex: true, // for hiddenapi check
@@ -44,6 +44,7 @@ java_library {
"//frameworks/base/apex/statsd:__subpackages__",
//TODO(b/146167933) remove this when framework is built with framework-statsd-stubs
"//frameworks/base",
+ "//frameworks/opt/net/wifi/service",
],
apex_available: [
"com.android.os.statsd",
@@ -51,31 +52,70 @@ java_library {
],
}
+stubs_defaults {
+ name: "framework-statsd-stubs-srcs-defaults",
+ srcs: [ ":framework-statsd-sources" ],
+ libs: [
+ // TODO(b/148218250): Change to android_system_stubs_current
+ "framework-all",
+ "framework-annotations-lib",
+ ],
+ sdk_version: "core_platform",
+}
+
droidstubs {
- name: "framework-statsd-stubs-docs",
+ name: "framework-statsd-stubs-srcs-publicapi",
defaults: [
- "framework-module-stubs-defaults-systemapi"
+ "framework-module-stubs-defaults-systemapi",
+ "framework-statsd-stubs-srcs-defaults",
],
- srcs: [
- ":framework-annotations",
- ":framework-statsd-sources",
+}
+
+droidstubs {
+ name: "framework-statsd-stubs-srcs-systemapi",
+ defaults: [
+ "framework-module-stubs-defaults-systemapi",
+ "framework-statsd-stubs-srcs-defaults",
],
- libs: [
- // TODO(b/148218250): Change to android_system_stubs_current
- "framework-all",
+}
+
+droidstubs {
+ name: "framework-statsd-api-module_libs_api",
+ defaults: [
+ "framework-module-api-defaults-module_libs_api",
+ "framework-statsd-stubs-srcs-defaults",
+ ],
+}
+
+droidstubs {
+ name: "framework-statsd-stubs-srcs-module_libs_api",
+ defaults: [
+ "framework-module-stubs-defaults-module_libs_api",
+ "framework-statsd-stubs-srcs-defaults",
],
+}
+
+java_library {
+ name: "framework-statsd-stubs-publicapi",
+ srcs: [ ":framework-statsd-stubs-srcs-publicapi" ],
+ // TODO(b/148218250): Change to current
+ libs: [ "framework-all" ],
sdk_version: "core_platform",
}
// TODO(b/146167933): Use these stubs in frameworks/base/Android.bp
java_library {
- name: "framework-statsd-stubs",
- srcs: [
- ":framework-statsd-stubs-docs",
- ],
- libs: [
- // TODO(b/148218250): Change to android_system_stubs_current
- "framework-all",
- ],
+ name: "framework-statsd-stubs-systemapi",
+ srcs: [ ":framework-statsd-stubs-srcs-systemapi" ],
+ // TODO(b/148218250): Change to system_current
+ libs: [ "framework-all" ],
+ sdk_version: "core_platform",
+}
+
+java_library {
+ name: "framework-statsd-stubs-module_libs_api",
+ srcs: [ ":framework-statsd-stubs-srcs-systemapi" ],
+ // TODO(b/148218250): Change to system_current
+ libs: [ "framework-all" ],
sdk_version: "core_platform",
}
diff --git a/apex/statsd/framework/java/android/os/StatsDimensionsValue.java b/apex/statsd/framework/java/android/os/StatsDimensionsValue.java
new file mode 100644
index 000000000000..886130fc5f14
--- /dev/null
+++ b/apex/statsd/framework/java/android/os/StatsDimensionsValue.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2018 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.os;
+
+import android.annotation.SystemApi;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Container for statsd dimension value information, corresponding to a
+ * stats_log.proto's DimensionValue.
+ *
+ * This consists of a field (an int representing a statsd atom field)
+ * and a value (which may be one of a number of types).
+ *
+ * <p>
+ * Only a single value is held, and it is necessarily one of the following types:
+ * {@link String}, int, long, boolean, float,
+ * or tuple (i.e. {@link List} of {@code StatsDimensionsValue}).
+ *
+ * The type of value held can be retrieved using {@link #getValueType()}, which returns one of the
+ * following ints, depending on the type of value:
+ * <ul>
+ * <li>{@link #STRING_VALUE_TYPE}</li>
+ * <li>{@link #INT_VALUE_TYPE}</li>
+ * <li>{@link #LONG_VALUE_TYPE}</li>
+ * <li>{@link #BOOLEAN_VALUE_TYPE}</li>
+ * <li>{@link #FLOAT_VALUE_TYPE}</li>
+ * <li>{@link #TUPLE_VALUE_TYPE}</li>
+ * </ul>
+ * Alternatively, this can be determined using {@link #isValueType(int)} with one of these constants
+ * as a parameter.
+ * The value itself can be retrieved using the correct get...Value() function for its type.
+ *
+ * <p>
+ * The field is always an int, and always exists; it can be obtained using {@link #getField()}.
+ *
+ *
+ * @hide
+ */
+@SystemApi
+public final class StatsDimensionsValue implements Parcelable {
+ private static final String TAG = "StatsDimensionsValue";
+
+ // Values of the value type correspond to stats_log.proto's DimensionValue fields.
+ // Keep constants in sync with services/include/android/os/StatsDimensionsValue.h.
+ /** Indicates that this holds a String. */
+ public static final int STRING_VALUE_TYPE = 2;
+ /** Indicates that this holds an int. */
+ public static final int INT_VALUE_TYPE = 3;
+ /** Indicates that this holds a long. */
+ public static final int LONG_VALUE_TYPE = 4;
+ /** Indicates that this holds a boolean. */
+ public static final int BOOLEAN_VALUE_TYPE = 5;
+ /** Indicates that this holds a float. */
+ public static final int FLOAT_VALUE_TYPE = 6;
+ /** Indicates that this holds a List of StatsDimensionsValues. */
+ public static final int TUPLE_VALUE_TYPE = 7;
+
+ /** Value of a stats_log.proto DimensionsValue.field. */
+ private final int mField;
+
+ /** Type of stats_log.proto DimensionsValue.value, according to the VALUE_TYPEs above. */
+ private final int mValueType;
+
+ /**
+ * Value of a stats_log.proto DimensionsValue.value.
+ * String, Integer, Long, Boolean, Float, or StatsDimensionsValue[].
+ */
+ private final Object mValue; // immutable or array of immutables
+
+ /**
+ * Creates a {@code StatsDimensionValue} from a parcel.
+ *
+ * @hide
+ */
+ public StatsDimensionsValue(Parcel in) {
+ mField = in.readInt();
+ mValueType = in.readInt();
+ mValue = readValueFromParcel(mValueType, in);
+ }
+
+ /**
+ * Return the field, i.e. the tag of a statsd atom.
+ *
+ * @return the field
+ */
+ public int getField() {
+ return mField;
+ }
+
+ /**
+ * Retrieve the String held, if any.
+ *
+ * @return the {@link String} held if {@link #getValueType()} == {@link #STRING_VALUE_TYPE},
+ * null otherwise
+ */
+ public String getStringValue() {
+ try {
+ if (mValueType == STRING_VALUE_TYPE) return (String) mValue;
+ } catch (ClassCastException e) {
+ Slog.w(TAG, "Failed to successfully get value", e);
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve the int held, if any.
+ *
+ * @return the int held if {@link #getValueType()} == {@link #INT_VALUE_TYPE}, 0 otherwise
+ */
+ public int getIntValue() {
+ try {
+ if (mValueType == INT_VALUE_TYPE) return (Integer) mValue;
+ } catch (ClassCastException e) {
+ Slog.w(TAG, "Failed to successfully get value", e);
+ }
+ return 0;
+ }
+
+ /**
+ * Retrieve the long held, if any.
+ *
+ * @return the long held if {@link #getValueType()} == {@link #LONG_VALUE_TYPE}, 0 otherwise
+ */
+ public long getLongValue() {
+ try {
+ if (mValueType == LONG_VALUE_TYPE) return (Long) mValue;
+ } catch (ClassCastException e) {
+ Slog.w(TAG, "Failed to successfully get value", e);
+ }
+ return 0;
+ }
+
+ /**
+ * Retrieve the boolean held, if any.
+ *
+ * @return the boolean held if {@link #getValueType()} == {@link #BOOLEAN_VALUE_TYPE},
+ * false otherwise
+ */
+ public boolean getBooleanValue() {
+ try {
+ if (mValueType == BOOLEAN_VALUE_TYPE) return (Boolean) mValue;
+ } catch (ClassCastException e) {
+ Slog.w(TAG, "Failed to successfully get value", e);
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve the float held, if any.
+ *
+ * @return the float held if {@link #getValueType()} == {@link #FLOAT_VALUE_TYPE}, 0 otherwise
+ */
+ public float getFloatValue() {
+ try {
+ if (mValueType == FLOAT_VALUE_TYPE) return (Float) mValue;
+ } catch (ClassCastException e) {
+ Slog.w(TAG, "Failed to successfully get value", e);
+ }
+ return 0;
+ }
+
+ /**
+ * Retrieve the tuple, in the form of a {@link List} of {@link StatsDimensionsValue}, held,
+ * if any.
+ *
+ * @return the {@link List} of {@link StatsDimensionsValue} held
+ * if {@link #getValueType()} == {@link #TUPLE_VALUE_TYPE},
+ * null otherwise
+ */
+ public List<StatsDimensionsValue> getTupleValueList() {
+ if (mValueType != TUPLE_VALUE_TYPE) {
+ return null;
+ }
+ try {
+ StatsDimensionsValue[] orig = (StatsDimensionsValue[]) mValue;
+ List<StatsDimensionsValue> copy = new ArrayList<>(orig.length);
+ // Shallow copy since StatsDimensionsValue is immutable anyway
+ for (int i = 0; i < orig.length; i++) {
+ copy.add(orig[i]);
+ }
+ return copy;
+ } catch (ClassCastException e) {
+ Slog.w(TAG, "Failed to successfully get value", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the constant representing the type of value stored, namely one of
+ * <ul>
+ * <li>{@link #STRING_VALUE_TYPE}</li>
+ * <li>{@link #INT_VALUE_TYPE}</li>
+ * <li>{@link #LONG_VALUE_TYPE}</li>
+ * <li>{@link #BOOLEAN_VALUE_TYPE}</li>
+ * <li>{@link #FLOAT_VALUE_TYPE}</li>
+ * <li>{@link #TUPLE_VALUE_TYPE}</li>
+ * </ul>
+ *
+ * @return the constant representing the type of value stored
+ */
+ public int getValueType() {
+ return mValueType;
+ }
+
+ /**
+ * Returns whether the type of value stored is equal to the given type.
+ *
+ * @param valueType int representing the type of value stored, as used in {@link #getValueType}
+ * @return true if {@link #getValueType()} is equal to {@code valueType}.
+ */
+ public boolean isValueType(int valueType) {
+ return mValueType == valueType;
+ }
+
+ /**
+ * Returns a String representing the information in this StatsDimensionValue.
+ * No guarantees are made about the format of this String.
+ *
+ * @return String representation
+ *
+ * @hide
+ */
+ // Follows the format of statsd's dimension.h toString.
+ public String toString() {
+ try {
+ StringBuilder sb = new StringBuilder();
+ sb.append(mField);
+ sb.append(":");
+ if (mValueType == TUPLE_VALUE_TYPE) {
+ sb.append("{");
+ StatsDimensionsValue[] sbvs = (StatsDimensionsValue[]) mValue;
+ for (int i = 0; i < sbvs.length; i++) {
+ sb.append(sbvs[i].toString());
+ sb.append("|");
+ }
+ sb.append("}");
+ } else {
+ sb.append(mValue.toString());
+ }
+ return sb.toString();
+ } catch (ClassCastException e) {
+ Slog.w(TAG, "Failed to successfully get value", e);
+ }
+ return "";
+ }
+
+ /**
+ * Parcelable Creator for StatsDimensionsValue.
+ */
+ public static final @android.annotation.NonNull
+ Parcelable.Creator<StatsDimensionsValue> CREATOR = new
+ Parcelable.Creator<StatsDimensionsValue>() {
+ public StatsDimensionsValue createFromParcel(Parcel in) {
+ return new StatsDimensionsValue(in);
+ }
+
+ public StatsDimensionsValue[] newArray(int size) {
+ return new StatsDimensionsValue[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mField);
+ out.writeInt(mValueType);
+ writeValueToParcel(mValueType, mValue, out, flags);
+ }
+
+ /** Writes mValue to a parcel. Returns true if succeeds. */
+ private static boolean writeValueToParcel(int valueType, Object value, Parcel out, int flags) {
+ try {
+ switch (valueType) {
+ case STRING_VALUE_TYPE:
+ out.writeString((String) value);
+ return true;
+ case INT_VALUE_TYPE:
+ out.writeInt((Integer) value);
+ return true;
+ case LONG_VALUE_TYPE:
+ out.writeLong((Long) value);
+ return true;
+ case BOOLEAN_VALUE_TYPE:
+ out.writeBoolean((Boolean) value);
+ return true;
+ case FLOAT_VALUE_TYPE:
+ out.writeFloat((Float) value);
+ return true;
+ case TUPLE_VALUE_TYPE: {
+ StatsDimensionsValue[] values = (StatsDimensionsValue[]) value;
+ out.writeInt(values.length);
+ for (int i = 0; i < values.length; i++) {
+ values[i].writeToParcel(out, flags);
+ }
+ return true;
+ }
+ default:
+ Slog.w(TAG, "readValue of an impossible type " + valueType);
+ return false;
+ }
+ } catch (ClassCastException e) {
+ Slog.w(TAG, "writeValue cast failed", e);
+ return false;
+ }
+ }
+
+ /** Reads mValue from a parcel. */
+ private static Object readValueFromParcel(int valueType, Parcel parcel) {
+ switch (valueType) {
+ case STRING_VALUE_TYPE:
+ return parcel.readString();
+ case INT_VALUE_TYPE:
+ return parcel.readInt();
+ case LONG_VALUE_TYPE:
+ return parcel.readLong();
+ case BOOLEAN_VALUE_TYPE:
+ return parcel.readBoolean();
+ case FLOAT_VALUE_TYPE:
+ return parcel.readFloat();
+ case TUPLE_VALUE_TYPE: {
+ final int sz = parcel.readInt();
+ StatsDimensionsValue[] values = new StatsDimensionsValue[sz];
+ for (int i = 0; i < sz; i++) {
+ values[i] = new StatsDimensionsValue(parcel);
+ }
+ return values;
+ }
+ default:
+ Slog.w(TAG, "readValue of an impossible type " + valueType);
+ return null;
+ }
+ }
+}
diff --git a/apex/statsd/jni/android_util_StatsLog.cpp b/apex/statsd/jni/android_util_StatsLog.cpp
new file mode 100644
index 000000000000..9d410eb1f836
--- /dev/null
+++ b/apex/statsd/jni/android_util_StatsLog.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#define LOG_NAMESPACE "StatsLog.tag."
+#define LOG_TAG "StatsLog_println"
+
+#include "jni.h"
+#include <log/log.h>
+#include <nativehelper/JNIHelp.h>
+#include "stats_buffer_writer.h"
+
+namespace android {
+
+static void android_util_StatsLog_write(JNIEnv* env, jobject clazz, jbyteArray buf, jint size,
+ jint atomId) {
+ if (buf == NULL) {
+ return;
+ }
+ jint actualSize = env->GetArrayLength(buf);
+ if (actualSize < size) {
+ return;
+ }
+
+ jbyte* bufferArray = env->GetByteArrayElements(buf, NULL);
+ if (bufferArray == NULL) {
+ return;
+ }
+
+ write_buffer_to_statsd((void*) bufferArray, size, atomId);
+
+ env->ReleaseByteArrayElements(buf, bufferArray, 0);
+}
+
+/*
+ * JNI registration.
+ */
+static const JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "writeImpl", "([BII)V", (void*) android_util_StatsLog_write },
+};
+
+int register_android_util_StatsLog(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "android/util/StatsLog", gMethods, NELEM(gMethods));
+}
+}; // namespace android
+
+/*
+ * JNI Initialization
+ */
+jint JNI_OnLoad(JavaVM* jvm, void* reserved) {
+ JNIEnv* e;
+ int status;
+
+ ALOGV("statsd : loading JNI\n");
+ // Check JNI version
+ if (jvm->GetEnv((void**)&e, JNI_VERSION_1_4)) {
+ ALOGE("JNI version mismatch error");
+ return JNI_ERR;
+ }
+ status = android::register_android_util_StatsLog(e);
+ if (status < 0) {
+ ALOGE("jni statsd registration failure, status: %d", status);
+ return JNI_ERR;
+ }
+ return JNI_VERSION_1_4;
+}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index 1e92826ee8a0..3e9a488fb5b8 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -516,6 +516,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
}
+ @Override // Binder call
+ public boolean checkPermission(String permission, int pid, int uid) {
+ StatsCompanion.enforceStatsCompanionPermission(mContext);
+ return mContext.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED;
+ }
// Statsd related code