diff options
Diffstat (limited to 'apex')
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 |