Loading apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java +9 −1 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ import java.util.Objects; /** * Class for representing how a blob can be shared. * * Note that this class is not thread-safe, callers need to take of synchronizing access. * Note that this class is not thread-safe, callers need to take care of synchronizing access. */ class BlobAccessMode { @Retention(RetentionPolicy.SOURCE) Loading Loading @@ -127,6 +127,14 @@ class BlobAccessMode { return false; } int getAccessType() { return mAccessType; } int getNumWhitelistedPackages() { return mWhitelistedPackages.size(); } void dump(IndentingPrintWriter fout) { fout.println("accessType: " + DebugUtils.flagsToString( BlobAccessMode.class, "ACCESS_TYPE_", mAccessType)); Loading apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java +53 −4 Original line number Diff line number Diff line Loading @@ -54,6 +54,8 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import android.util.StatsEvent; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; Loading @@ -61,6 +63,8 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; import com.android.server.blob.BlobStoreManagerService.DumpArgs; import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; Loading Loading @@ -349,14 +353,16 @@ class BlobMetadata { } catch (ErrnoException e) { throw e.rethrowAsIOException(); } synchronized (mMetadataLock) { return createRevocableFdLocked(fd, callingPackage); try { return createRevocableFd(fd, callingPackage); } catch (IOException e) { IoUtils.closeQuietly(fd); throw e; } } @GuardedBy("mMetadataLock") @NonNull private ParcelFileDescriptor createRevocableFdLocked(FileDescriptor fd, private ParcelFileDescriptor createRevocableFd(FileDescriptor fd, String callingPackage) throws IOException { final RevocableFileDescriptor revocableFd = new RevocableFileDescriptor(mContext, fd); Loading Loading @@ -410,6 +416,49 @@ class BlobMetadata { return true; } StatsEvent dumpAsStatsEvent(int atomTag) { synchronized (mMetadataLock) { ProtoOutputStream proto = new ProtoOutputStream(); // Write Committer data to proto format for (int i = 0, size = mCommitters.size(); i < size; ++i) { final Committer committer = mCommitters.valueAt(i); final long token = proto.start( BlobStatsEventProto.BlobCommitterListProto.COMMITTER); proto.write(BlobStatsEventProto.BlobCommitterProto.UID, committer.uid); proto.write(BlobStatsEventProto.BlobCommitterProto.COMMIT_TIMESTAMP_MILLIS, committer.commitTimeMs); proto.write(BlobStatsEventProto.BlobCommitterProto.ACCESS_MODE, committer.blobAccessMode.getAccessType()); proto.write(BlobStatsEventProto.BlobCommitterProto.NUM_WHITELISTED_PACKAGE, committer.blobAccessMode.getNumWhitelistedPackages()); proto.end(token); } final byte[] committersBytes = proto.getBytes(); proto = new ProtoOutputStream(); // Write Leasee data to proto format for (int i = 0, size = mLeasees.size(); i < size; ++i) { final Leasee leasee = mLeasees.valueAt(i); final long token = proto.start(BlobStatsEventProto.BlobLeaseeListProto.LEASEE); proto.write(BlobStatsEventProto.BlobLeaseeProto.UID, leasee.uid); proto.write(BlobStatsEventProto.BlobLeaseeProto.LEASE_EXPIRY_TIMESTAMP_MILLIS, leasee.expiryTimeMillis); proto.end(token); } final byte[] leaseesBytes = proto.getBytes(); // Construct the StatsEvent to represent this Blob return StatsEvent.newBuilder() .setAtomId(atomTag) .writeLong(mBlobId) .writeLong(getSize()) .writeLong(mBlobHandle.getExpiryTimeMillis()) .writeByteArray(committersBytes) .writeByteArray(leaseesBytes) .build(); } } void dump(IndentingPrintWriter fout, DumpArgs dumpArgs) { fout.println("blobHandle:"); fout.increaseIndent(); Loading apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java +3 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,9 @@ class BlobStoreConfig { public static final int XML_VERSION_CURRENT = XML_VERSION_ADD_SESSION_CREATION_TIME; public static final long INVALID_BLOB_ID = 0; public static final long INVALID_BLOB_SIZE = 0; private static final String ROOT_DIR_NAME = "blobstore"; private static final String BLOBS_DIR_NAME = "blobs"; private static final String SESSIONS_INDEX_FILE_NAME = "sessions_index.xml"; Loading apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java +86 −1 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.os.UserHandle.USER_CURRENT; import static android.os.UserHandle.USER_NULL; import static com.android.server.blob.BlobStoreConfig.INVALID_BLOB_ID; import static com.android.server.blob.BlobStoreConfig.INVALID_BLOB_SIZE; import static com.android.server.blob.BlobStoreConfig.LOGV; import static com.android.server.blob.BlobStoreConfig.TAG; import static com.android.server.blob.BlobStoreConfig.XML_VERSION_CURRENT; Loading @@ -48,6 +50,7 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.StatsManager; import android.app.blob.BlobHandle; import android.app.blob.BlobInfo; import android.app.blob.IBlobStoreManager; Loading Loading @@ -80,6 +83,7 @@ import android.util.ExceptionUtils; import android.util.LongSparseArray; import android.util.Slog; import android.util.SparseArray; import android.util.StatsEvent; import android.util.Xml; import com.android.internal.annotations.GuardedBy; Loading @@ -88,6 +92,7 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; Loading Loading @@ -159,6 +164,8 @@ public class BlobStoreManagerService extends SystemService { new SessionStateChangeListener(); private PackageManagerInternal mPackageManagerInternal; private StatsManager mStatsManager; private StatsPullAtomCallbackImpl mStatsCallbackImpl = new StatsPullAtomCallbackImpl(); private final Runnable mSaveBlobsInfoRunnable = this::writeBlobsInfo; private final Runnable mSaveSessionsRunnable = this::writeBlobSessions; Loading Loading @@ -192,6 +199,7 @@ public class BlobStoreManagerService extends SystemService { LocalServices.addService(BlobStoreManagerInternal.class, new LocalService()); mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mStatsManager = getContext().getSystemService(StatsManager.class); registerReceivers(); LocalServices.getService(StorageStatsManagerInternal.class) .registerStorageStatsAugmenter(new BlobStorageStatsAugmenter(), TAG); Loading @@ -207,6 +215,7 @@ public class BlobStoreManagerService extends SystemService { readBlobSessionsLocked(allPackages); readBlobsInfoLocked(allPackages); } registerBlobStorePuller(); } else if (phase == PHASE_BOOT_COMPLETED) { BlobStoreIdleJobService.schedule(mContext); } Loading @@ -219,7 +228,7 @@ public class BlobStoreManagerService extends SystemService { long sessionId; do { sessionId = Math.abs(mRandom.nextLong()); if (mKnownBlobIds.indexOf(sessionId) < 0 && sessionId != 0) { if (mKnownBlobIds.indexOf(sessionId) < 0 && sessionId != INVALID_BLOB_ID) { return sessionId; } } while (n++ < 32); Loading Loading @@ -376,9 +385,23 @@ public class BlobStoreManagerService extends SystemService { .get(blobHandle); if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller( callingPackage, callingUid)) { if (blobMetadata == null) { FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid, INVALID_BLOB_ID, INVALID_BLOB_SIZE, FrameworkStatsLog.BLOB_OPENED__RESULT__BLOB_DNE); } else { FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid, blobMetadata.getBlobId(), blobMetadata.getSize(), FrameworkStatsLog.BLOB_LEASED__RESULT__ACCESS_NOT_ALLOWED); } throw new SecurityException("Caller not allowed to access " + blobHandle + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage); } FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid, blobMetadata.getBlobId(), blobMetadata.getSize(), FrameworkStatsLog.BLOB_OPENED__RESULT__SUCCESS); return blobMetadata.openForRead(callingPackage); } } Loading @@ -391,19 +414,41 @@ public class BlobStoreManagerService extends SystemService { .get(blobHandle); if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller( callingPackage, callingUid)) { if (blobMetadata == null) { FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid, INVALID_BLOB_ID, INVALID_BLOB_SIZE, FrameworkStatsLog.BLOB_LEASED__RESULT__BLOB_DNE); } else { FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid, blobMetadata.getBlobId(), blobMetadata.getSize(), FrameworkStatsLog.BLOB_LEASED__RESULT__ACCESS_NOT_ALLOWED); } throw new SecurityException("Caller not allowed to access " + blobHandle + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage); } if (leaseExpiryTimeMillis != 0 && blobHandle.expiryTimeMillis != 0 && leaseExpiryTimeMillis > blobHandle.expiryTimeMillis) { FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid, blobMetadata.getBlobId(), blobMetadata.getSize(), FrameworkStatsLog.BLOB_LEASED__RESULT__LEASE_EXPIRY_INVALID); throw new IllegalArgumentException( "Lease expiry cannot be later than blobs expiry time"); } if (blobMetadata.getSize() > getRemainingLeaseQuotaBytesInternal(callingUid, callingPackage)) { FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid, blobMetadata.getBlobId(), blobMetadata.getSize(), FrameworkStatsLog.BLOB_LEASED__RESULT__DATA_SIZE_LIMIT_EXCEEDED); throw new LimitExceededException("Total amount of data with an active lease" + " is exceeding the max limit"); } FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid, blobMetadata.getBlobId(), blobMetadata.getSize(), FrameworkStatsLog.BLOB_LEASED__RESULT__SUCCESS); blobMetadata.addOrReplaceLeasee(callingPackage, callingUid, descriptionResId, description, leaseExpiryTimeMillis); if (LOGV) { Loading Loading @@ -587,6 +632,9 @@ public class BlobStoreManagerService extends SystemService { blob.addOrReplaceCommitter(newCommitter); try { writeBlobsInfoLocked(); FrameworkStatsLog.write(FrameworkStatsLog.BLOB_COMMITTED, session.getOwnerUid(), blob.getBlobId(), blob.getSize(), FrameworkStatsLog.BLOB_COMMITTED__RESULT__SUCCESS); session.sendCommitCallbackResult(COMMIT_RESULT_SUCCESS); } catch (Exception e) { if (existingCommitter == null) { Loading @@ -595,6 +643,9 @@ public class BlobStoreManagerService extends SystemService { blob.addOrReplaceCommitter(existingCommitter); } Slog.d(TAG, "Error committing the blob", e); FrameworkStatsLog.write(FrameworkStatsLog.BLOB_COMMITTED, session.getOwnerUid(), blob.getBlobId(), blob.getSize(), FrameworkStatsLog.BLOB_COMMITTED__RESULT__ERROR_DURING_COMMIT); session.sendCommitCallbackResult(COMMIT_RESULT_ERROR); } getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid())) Loading Loading @@ -1684,6 +1735,40 @@ public class BlobStoreManagerService extends SystemService { } } private void registerBlobStorePuller() { mStatsManager.setPullAtomCallback( FrameworkStatsLog.BLOB_INFO, null, // use default PullAtomMetadata values BackgroundThread.getExecutor(), mStatsCallbackImpl ); } private class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback { @Override public int onPullAtom(int atomTag, List<StatsEvent> data) { switch (atomTag) { case FrameworkStatsLog.BLOB_INFO: return pullBlobData(atomTag, data); default: throw new UnsupportedOperationException("Unknown tagId=" + atomTag); } } } private int pullBlobData(int atomTag, List<StatsEvent> data) { synchronized (mBlobsLock) { for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) { final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i); for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) { final BlobMetadata blob = userBlobs.valueAt(j); data.add(blob.dumpAsStatsEvent(atomTag)); } } } return StatsManager.PULL_SUCCESS; } private class LocalService extends BlobStoreManagerInternal { @Override public void onIdleMaintenance() { Loading apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java +55 −32 Original line number Diff line number Diff line Loading @@ -53,12 +53,15 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; 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 libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; Loading Loading @@ -207,27 +210,37 @@ class BlobStoreSession extends IBlobStoreSession.Stub { throw new IllegalStateException("Not allowed to write in state: " + stateToString(mState)); } } FileDescriptor fd = null; try { return openWriteLocked(offsetBytes, lengthBytes); fd = openWriteInternal(offsetBytes, lengthBytes); final RevocableFileDescriptor revocableFd = new RevocableFileDescriptor(mContext, fd); synchronized (mSessionLock) { if (mState != STATE_OPENED) { IoUtils.closeQuietly(fd); throw new IllegalStateException("Not allowed to write in state: " + stateToString(mState)); } trackRevocableFdLocked(revocableFd); return revocableFd.getRevocableFileDescriptor(); } } catch (IOException e) { IoUtils.closeQuietly(fd); throw ExceptionUtils.wrap(e); } } } @GuardedBy("mSessionLock") @NonNull private ParcelFileDescriptor openWriteLocked(@BytesLong long offsetBytes, private FileDescriptor openWriteInternal(@BytesLong long offsetBytes, @BytesLong long lengthBytes) throws IOException { // TODO: Add limit on active open sessions/writes/reads FileDescriptor fd = null; try { final File sessionFile = getSessionFile(); if (sessionFile == null) { throw new IllegalStateException("Couldn't get the file for this session"); } fd = Os.open(sessionFile.getPath(), O_CREAT | O_RDWR, 0600); final FileDescriptor fd = Os.open(sessionFile.getPath(), O_CREAT | O_RDWR, 0600); if (offsetBytes > 0) { final long curOffset = Os.lseek(fd, offsetBytes, SEEK_SET); if (curOffset != offsetBytes) { Loading @@ -238,10 +251,10 @@ class BlobStoreSession extends IBlobStoreSession.Stub { if (lengthBytes > 0) { mContext.getSystemService(StorageManager.class).allocateBytes(fd, lengthBytes); } return fd; } catch (ErrnoException e) { e.rethrowAsIOException(); throw e.rethrowAsIOException(); } return createRevocableFdLocked(fd); } @Override Loading @@ -253,29 +266,40 @@ class BlobStoreSession extends IBlobStoreSession.Stub { throw new IllegalStateException("Not allowed to read in state: " + stateToString(mState)); } } FileDescriptor fd = null; try { return openReadLocked(); fd = openReadInternal(); final RevocableFileDescriptor revocableFd = new RevocableFileDescriptor(mContext, fd); synchronized (mSessionLock) { if (mState != STATE_OPENED) { IoUtils.closeQuietly(fd); throw new IllegalStateException("Not allowed to read in state: " + stateToString(mState)); } trackRevocableFdLocked(revocableFd); return revocableFd.getRevocableFileDescriptor(); } } catch (IOException e) { IoUtils.closeQuietly(fd); throw ExceptionUtils.wrap(e); } } } @GuardedBy("mSessionLock") @NonNull private ParcelFileDescriptor openReadLocked() throws IOException { FileDescriptor fd = null; private FileDescriptor openReadInternal() throws IOException { try { final File sessionFile = getSessionFile(); if (sessionFile == null) { throw new IllegalStateException("Couldn't get the file for this session"); } fd = Os.open(sessionFile.getPath(), O_RDONLY, 0); final FileDescriptor fd = Os.open(sessionFile.getPath(), O_RDONLY, 0); return fd; } catch (ErrnoException e) { e.rethrowAsIOException(); throw e.rethrowAsIOException(); } return createRevocableFdLocked(fd); } @Override Loading Loading @@ -396,7 +420,7 @@ class BlobStoreSession extends IBlobStoreSession.Stub { } mState = state; revokeAllFdsLocked(); revokeAllFds(); if (sendCallback) { mListener.onStateChanged(this); Loading Loading @@ -427,26 +451,26 @@ class BlobStoreSession extends IBlobStoreSession.Stub { + ") didn't match the given BlobHandle.digest (" + BlobHandle.safeDigest(mBlobHandle.digest) + ")"); mState = STATE_VERIFIED_INVALID; FrameworkStatsLog.write(FrameworkStatsLog.BLOB_COMMITTED, getOwnerUid(), mSessionId, getSize(), FrameworkStatsLog.BLOB_COMMITTED__RESULT__DIGEST_MISMATCH); sendCommitCallbackResult(COMMIT_RESULT_ERROR); } mListener.onStateChanged(this); } } @GuardedBy("mSessionLock") private void revokeAllFdsLocked() { private void revokeAllFds() { synchronized (mRevocableFds) { for (int i = mRevocableFds.size() - 1; i >= 0; --i) { mRevocableFds.get(i).revoke(); } mRevocableFds.clear(); } } @GuardedBy("mSessionLock") @NonNull private ParcelFileDescriptor createRevocableFdLocked(FileDescriptor fd) throws IOException { final RevocableFileDescriptor revocableFd = new RevocableFileDescriptor(mContext, fd); private void trackRevocableFdLocked(RevocableFileDescriptor revocableFd) { synchronized (mRevocableFds) { mRevocableFds.add(revocableFd); } Loading @@ -455,7 +479,6 @@ class BlobStoreSession extends IBlobStoreSession.Stub { mRevocableFds.remove(revocableFd); } }); return revocableFd.getRevocableFileDescriptor(); } @Nullable Loading Loading
apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java +9 −1 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ import java.util.Objects; /** * Class for representing how a blob can be shared. * * Note that this class is not thread-safe, callers need to take of synchronizing access. * Note that this class is not thread-safe, callers need to take care of synchronizing access. */ class BlobAccessMode { @Retention(RetentionPolicy.SOURCE) Loading Loading @@ -127,6 +127,14 @@ class BlobAccessMode { return false; } int getAccessType() { return mAccessType; } int getNumWhitelistedPackages() { return mWhitelistedPackages.size(); } void dump(IndentingPrintWriter fout) { fout.println("accessType: " + DebugUtils.flagsToString( BlobAccessMode.class, "ACCESS_TYPE_", mAccessType)); Loading
apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java +53 −4 Original line number Diff line number Diff line Loading @@ -54,6 +54,8 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import android.util.StatsEvent; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; Loading @@ -61,6 +63,8 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; import com.android.server.blob.BlobStoreManagerService.DumpArgs; import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; Loading Loading @@ -349,14 +353,16 @@ class BlobMetadata { } catch (ErrnoException e) { throw e.rethrowAsIOException(); } synchronized (mMetadataLock) { return createRevocableFdLocked(fd, callingPackage); try { return createRevocableFd(fd, callingPackage); } catch (IOException e) { IoUtils.closeQuietly(fd); throw e; } } @GuardedBy("mMetadataLock") @NonNull private ParcelFileDescriptor createRevocableFdLocked(FileDescriptor fd, private ParcelFileDescriptor createRevocableFd(FileDescriptor fd, String callingPackage) throws IOException { final RevocableFileDescriptor revocableFd = new RevocableFileDescriptor(mContext, fd); Loading Loading @@ -410,6 +416,49 @@ class BlobMetadata { return true; } StatsEvent dumpAsStatsEvent(int atomTag) { synchronized (mMetadataLock) { ProtoOutputStream proto = new ProtoOutputStream(); // Write Committer data to proto format for (int i = 0, size = mCommitters.size(); i < size; ++i) { final Committer committer = mCommitters.valueAt(i); final long token = proto.start( BlobStatsEventProto.BlobCommitterListProto.COMMITTER); proto.write(BlobStatsEventProto.BlobCommitterProto.UID, committer.uid); proto.write(BlobStatsEventProto.BlobCommitterProto.COMMIT_TIMESTAMP_MILLIS, committer.commitTimeMs); proto.write(BlobStatsEventProto.BlobCommitterProto.ACCESS_MODE, committer.blobAccessMode.getAccessType()); proto.write(BlobStatsEventProto.BlobCommitterProto.NUM_WHITELISTED_PACKAGE, committer.blobAccessMode.getNumWhitelistedPackages()); proto.end(token); } final byte[] committersBytes = proto.getBytes(); proto = new ProtoOutputStream(); // Write Leasee data to proto format for (int i = 0, size = mLeasees.size(); i < size; ++i) { final Leasee leasee = mLeasees.valueAt(i); final long token = proto.start(BlobStatsEventProto.BlobLeaseeListProto.LEASEE); proto.write(BlobStatsEventProto.BlobLeaseeProto.UID, leasee.uid); proto.write(BlobStatsEventProto.BlobLeaseeProto.LEASE_EXPIRY_TIMESTAMP_MILLIS, leasee.expiryTimeMillis); proto.end(token); } final byte[] leaseesBytes = proto.getBytes(); // Construct the StatsEvent to represent this Blob return StatsEvent.newBuilder() .setAtomId(atomTag) .writeLong(mBlobId) .writeLong(getSize()) .writeLong(mBlobHandle.getExpiryTimeMillis()) .writeByteArray(committersBytes) .writeByteArray(leaseesBytes) .build(); } } void dump(IndentingPrintWriter fout, DumpArgs dumpArgs) { fout.println("blobHandle:"); fout.increaseIndent(); Loading
apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java +3 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,9 @@ class BlobStoreConfig { public static final int XML_VERSION_CURRENT = XML_VERSION_ADD_SESSION_CREATION_TIME; public static final long INVALID_BLOB_ID = 0; public static final long INVALID_BLOB_SIZE = 0; private static final String ROOT_DIR_NAME = "blobstore"; private static final String BLOBS_DIR_NAME = "blobs"; private static final String SESSIONS_INDEX_FILE_NAME = "sessions_index.xml"; Loading
apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java +86 −1 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.os.UserHandle.USER_CURRENT; import static android.os.UserHandle.USER_NULL; import static com.android.server.blob.BlobStoreConfig.INVALID_BLOB_ID; import static com.android.server.blob.BlobStoreConfig.INVALID_BLOB_SIZE; import static com.android.server.blob.BlobStoreConfig.LOGV; import static com.android.server.blob.BlobStoreConfig.TAG; import static com.android.server.blob.BlobStoreConfig.XML_VERSION_CURRENT; Loading @@ -48,6 +50,7 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.StatsManager; import android.app.blob.BlobHandle; import android.app.blob.BlobInfo; import android.app.blob.IBlobStoreManager; Loading Loading @@ -80,6 +83,7 @@ import android.util.ExceptionUtils; import android.util.LongSparseArray; import android.util.Slog; import android.util.SparseArray; import android.util.StatsEvent; import android.util.Xml; import com.android.internal.annotations.GuardedBy; Loading @@ -88,6 +92,7 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; Loading Loading @@ -159,6 +164,8 @@ public class BlobStoreManagerService extends SystemService { new SessionStateChangeListener(); private PackageManagerInternal mPackageManagerInternal; private StatsManager mStatsManager; private StatsPullAtomCallbackImpl mStatsCallbackImpl = new StatsPullAtomCallbackImpl(); private final Runnable mSaveBlobsInfoRunnable = this::writeBlobsInfo; private final Runnable mSaveSessionsRunnable = this::writeBlobSessions; Loading Loading @@ -192,6 +199,7 @@ public class BlobStoreManagerService extends SystemService { LocalServices.addService(BlobStoreManagerInternal.class, new LocalService()); mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mStatsManager = getContext().getSystemService(StatsManager.class); registerReceivers(); LocalServices.getService(StorageStatsManagerInternal.class) .registerStorageStatsAugmenter(new BlobStorageStatsAugmenter(), TAG); Loading @@ -207,6 +215,7 @@ public class BlobStoreManagerService extends SystemService { readBlobSessionsLocked(allPackages); readBlobsInfoLocked(allPackages); } registerBlobStorePuller(); } else if (phase == PHASE_BOOT_COMPLETED) { BlobStoreIdleJobService.schedule(mContext); } Loading @@ -219,7 +228,7 @@ public class BlobStoreManagerService extends SystemService { long sessionId; do { sessionId = Math.abs(mRandom.nextLong()); if (mKnownBlobIds.indexOf(sessionId) < 0 && sessionId != 0) { if (mKnownBlobIds.indexOf(sessionId) < 0 && sessionId != INVALID_BLOB_ID) { return sessionId; } } while (n++ < 32); Loading Loading @@ -376,9 +385,23 @@ public class BlobStoreManagerService extends SystemService { .get(blobHandle); if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller( callingPackage, callingUid)) { if (blobMetadata == null) { FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid, INVALID_BLOB_ID, INVALID_BLOB_SIZE, FrameworkStatsLog.BLOB_OPENED__RESULT__BLOB_DNE); } else { FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid, blobMetadata.getBlobId(), blobMetadata.getSize(), FrameworkStatsLog.BLOB_LEASED__RESULT__ACCESS_NOT_ALLOWED); } throw new SecurityException("Caller not allowed to access " + blobHandle + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage); } FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid, blobMetadata.getBlobId(), blobMetadata.getSize(), FrameworkStatsLog.BLOB_OPENED__RESULT__SUCCESS); return blobMetadata.openForRead(callingPackage); } } Loading @@ -391,19 +414,41 @@ public class BlobStoreManagerService extends SystemService { .get(blobHandle); if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller( callingPackage, callingUid)) { if (blobMetadata == null) { FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid, INVALID_BLOB_ID, INVALID_BLOB_SIZE, FrameworkStatsLog.BLOB_LEASED__RESULT__BLOB_DNE); } else { FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid, blobMetadata.getBlobId(), blobMetadata.getSize(), FrameworkStatsLog.BLOB_LEASED__RESULT__ACCESS_NOT_ALLOWED); } throw new SecurityException("Caller not allowed to access " + blobHandle + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage); } if (leaseExpiryTimeMillis != 0 && blobHandle.expiryTimeMillis != 0 && leaseExpiryTimeMillis > blobHandle.expiryTimeMillis) { FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid, blobMetadata.getBlobId(), blobMetadata.getSize(), FrameworkStatsLog.BLOB_LEASED__RESULT__LEASE_EXPIRY_INVALID); throw new IllegalArgumentException( "Lease expiry cannot be later than blobs expiry time"); } if (blobMetadata.getSize() > getRemainingLeaseQuotaBytesInternal(callingUid, callingPackage)) { FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid, blobMetadata.getBlobId(), blobMetadata.getSize(), FrameworkStatsLog.BLOB_LEASED__RESULT__DATA_SIZE_LIMIT_EXCEEDED); throw new LimitExceededException("Total amount of data with an active lease" + " is exceeding the max limit"); } FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid, blobMetadata.getBlobId(), blobMetadata.getSize(), FrameworkStatsLog.BLOB_LEASED__RESULT__SUCCESS); blobMetadata.addOrReplaceLeasee(callingPackage, callingUid, descriptionResId, description, leaseExpiryTimeMillis); if (LOGV) { Loading Loading @@ -587,6 +632,9 @@ public class BlobStoreManagerService extends SystemService { blob.addOrReplaceCommitter(newCommitter); try { writeBlobsInfoLocked(); FrameworkStatsLog.write(FrameworkStatsLog.BLOB_COMMITTED, session.getOwnerUid(), blob.getBlobId(), blob.getSize(), FrameworkStatsLog.BLOB_COMMITTED__RESULT__SUCCESS); session.sendCommitCallbackResult(COMMIT_RESULT_SUCCESS); } catch (Exception e) { if (existingCommitter == null) { Loading @@ -595,6 +643,9 @@ public class BlobStoreManagerService extends SystemService { blob.addOrReplaceCommitter(existingCommitter); } Slog.d(TAG, "Error committing the blob", e); FrameworkStatsLog.write(FrameworkStatsLog.BLOB_COMMITTED, session.getOwnerUid(), blob.getBlobId(), blob.getSize(), FrameworkStatsLog.BLOB_COMMITTED__RESULT__ERROR_DURING_COMMIT); session.sendCommitCallbackResult(COMMIT_RESULT_ERROR); } getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid())) Loading Loading @@ -1684,6 +1735,40 @@ public class BlobStoreManagerService extends SystemService { } } private void registerBlobStorePuller() { mStatsManager.setPullAtomCallback( FrameworkStatsLog.BLOB_INFO, null, // use default PullAtomMetadata values BackgroundThread.getExecutor(), mStatsCallbackImpl ); } private class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback { @Override public int onPullAtom(int atomTag, List<StatsEvent> data) { switch (atomTag) { case FrameworkStatsLog.BLOB_INFO: return pullBlobData(atomTag, data); default: throw new UnsupportedOperationException("Unknown tagId=" + atomTag); } } } private int pullBlobData(int atomTag, List<StatsEvent> data) { synchronized (mBlobsLock) { for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) { final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i); for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) { final BlobMetadata blob = userBlobs.valueAt(j); data.add(blob.dumpAsStatsEvent(atomTag)); } } } return StatsManager.PULL_SUCCESS; } private class LocalService extends BlobStoreManagerInternal { @Override public void onIdleMaintenance() { Loading
apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java +55 −32 Original line number Diff line number Diff line Loading @@ -53,12 +53,15 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; 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 libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; Loading Loading @@ -207,27 +210,37 @@ class BlobStoreSession extends IBlobStoreSession.Stub { throw new IllegalStateException("Not allowed to write in state: " + stateToString(mState)); } } FileDescriptor fd = null; try { return openWriteLocked(offsetBytes, lengthBytes); fd = openWriteInternal(offsetBytes, lengthBytes); final RevocableFileDescriptor revocableFd = new RevocableFileDescriptor(mContext, fd); synchronized (mSessionLock) { if (mState != STATE_OPENED) { IoUtils.closeQuietly(fd); throw new IllegalStateException("Not allowed to write in state: " + stateToString(mState)); } trackRevocableFdLocked(revocableFd); return revocableFd.getRevocableFileDescriptor(); } } catch (IOException e) { IoUtils.closeQuietly(fd); throw ExceptionUtils.wrap(e); } } } @GuardedBy("mSessionLock") @NonNull private ParcelFileDescriptor openWriteLocked(@BytesLong long offsetBytes, private FileDescriptor openWriteInternal(@BytesLong long offsetBytes, @BytesLong long lengthBytes) throws IOException { // TODO: Add limit on active open sessions/writes/reads FileDescriptor fd = null; try { final File sessionFile = getSessionFile(); if (sessionFile == null) { throw new IllegalStateException("Couldn't get the file for this session"); } fd = Os.open(sessionFile.getPath(), O_CREAT | O_RDWR, 0600); final FileDescriptor fd = Os.open(sessionFile.getPath(), O_CREAT | O_RDWR, 0600); if (offsetBytes > 0) { final long curOffset = Os.lseek(fd, offsetBytes, SEEK_SET); if (curOffset != offsetBytes) { Loading @@ -238,10 +251,10 @@ class BlobStoreSession extends IBlobStoreSession.Stub { if (lengthBytes > 0) { mContext.getSystemService(StorageManager.class).allocateBytes(fd, lengthBytes); } return fd; } catch (ErrnoException e) { e.rethrowAsIOException(); throw e.rethrowAsIOException(); } return createRevocableFdLocked(fd); } @Override Loading @@ -253,29 +266,40 @@ class BlobStoreSession extends IBlobStoreSession.Stub { throw new IllegalStateException("Not allowed to read in state: " + stateToString(mState)); } } FileDescriptor fd = null; try { return openReadLocked(); fd = openReadInternal(); final RevocableFileDescriptor revocableFd = new RevocableFileDescriptor(mContext, fd); synchronized (mSessionLock) { if (mState != STATE_OPENED) { IoUtils.closeQuietly(fd); throw new IllegalStateException("Not allowed to read in state: " + stateToString(mState)); } trackRevocableFdLocked(revocableFd); return revocableFd.getRevocableFileDescriptor(); } } catch (IOException e) { IoUtils.closeQuietly(fd); throw ExceptionUtils.wrap(e); } } } @GuardedBy("mSessionLock") @NonNull private ParcelFileDescriptor openReadLocked() throws IOException { FileDescriptor fd = null; private FileDescriptor openReadInternal() throws IOException { try { final File sessionFile = getSessionFile(); if (sessionFile == null) { throw new IllegalStateException("Couldn't get the file for this session"); } fd = Os.open(sessionFile.getPath(), O_RDONLY, 0); final FileDescriptor fd = Os.open(sessionFile.getPath(), O_RDONLY, 0); return fd; } catch (ErrnoException e) { e.rethrowAsIOException(); throw e.rethrowAsIOException(); } return createRevocableFdLocked(fd); } @Override Loading Loading @@ -396,7 +420,7 @@ class BlobStoreSession extends IBlobStoreSession.Stub { } mState = state; revokeAllFdsLocked(); revokeAllFds(); if (sendCallback) { mListener.onStateChanged(this); Loading Loading @@ -427,26 +451,26 @@ class BlobStoreSession extends IBlobStoreSession.Stub { + ") didn't match the given BlobHandle.digest (" + BlobHandle.safeDigest(mBlobHandle.digest) + ")"); mState = STATE_VERIFIED_INVALID; FrameworkStatsLog.write(FrameworkStatsLog.BLOB_COMMITTED, getOwnerUid(), mSessionId, getSize(), FrameworkStatsLog.BLOB_COMMITTED__RESULT__DIGEST_MISMATCH); sendCommitCallbackResult(COMMIT_RESULT_ERROR); } mListener.onStateChanged(this); } } @GuardedBy("mSessionLock") private void revokeAllFdsLocked() { private void revokeAllFds() { synchronized (mRevocableFds) { for (int i = mRevocableFds.size() - 1; i >= 0; --i) { mRevocableFds.get(i).revoke(); } mRevocableFds.clear(); } } @GuardedBy("mSessionLock") @NonNull private ParcelFileDescriptor createRevocableFdLocked(FileDescriptor fd) throws IOException { final RevocableFileDescriptor revocableFd = new RevocableFileDescriptor(mContext, fd); private void trackRevocableFdLocked(RevocableFileDescriptor revocableFd) { synchronized (mRevocableFds) { mRevocableFds.add(revocableFd); } Loading @@ -455,7 +479,6 @@ class BlobStoreSession extends IBlobStoreSession.Stub { mRevocableFds.remove(revocableFd); } }); return revocableFd.getRevocableFileDescriptor(); } @Nullable Loading