diff options
author | Sudheer Shanka <sudheersai@google.com> | 2020-01-21 13:32:04 -0800 |
---|---|---|
committer | Sudheer Shanka <sudheersai@google.com> | 2020-01-23 18:02:20 -0800 |
commit | 22f0b166e89b7b8ad8e82a4e2dd359e692e0ae84 (patch) | |
tree | bc460c431a0496fdd8f9f30780adfcf385b0017b /apex/blobstore | |
parent | f6e23b96b5f289a4c6dd4884288e2eeb42713270 (diff) |
Delete sessions belonging to uninstalled packages.
+ Remove uninstalled packages from committers, leasees list.
Bug: 143559646
Test: atest ./hostsidetests/blobstore/src/com/android/cts/host/blob/DataCleanupTest.java
Change-Id: I54d2777d92615a8bc1887e3e31c9d2d76d68bece
Diffstat (limited to 'apex/blobstore')
-rw-r--r-- | apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java | 38 | ||||
-rw-r--r-- | apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java | 170 |
2 files changed, 196 insertions, 12 deletions
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 566eb31447af..e9838d6b9712 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java @@ -43,6 +43,7 @@ import android.system.Os; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; +import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; @@ -52,6 +53,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.util.Objects; @@ -82,6 +84,9 @@ class BlobMetadata { private final ArrayMap<String, ArraySet<RevocableFileDescriptor>> mRevocableFds = new ArrayMap<>(); + // Do not access this directly, instead use getSessionFile(). + private File mBlobFile; + BlobMetadata(Context context, long blobId, BlobHandle blobHandle, int userId) { mContext = context; this.blobId = blobId; @@ -101,6 +106,20 @@ class BlobMetadata { } } + void removeCommitter(@NonNull String packageName, int uid) { + synchronized (mMetadataLock) { + mCommitters.removeIf((committer) -> + committer.uid == uid && committer.packageName.equals(packageName)); + } + } + + void removeInvalidCommitters(SparseArray<String> packages) { + synchronized (mMetadataLock) { + mCommitters.removeIf(committer -> + !committer.packageName.equals(packages.get(committer.uid))); + } + } + @Nullable Committer getExistingCommitter(@NonNull Committer newCommitter) { synchronized (mCommitters) { @@ -125,7 +144,15 @@ class BlobMetadata { void removeLeasee(String packageName, int uid) { synchronized (mMetadataLock) { - mLeasees.remove(new Accessor(packageName, uid)); + mLeasees.removeIf((leasee) -> + leasee.uid == uid && leasee.packageName.equals(packageName)); + } + } + + void removeInvalidLeasees(SparseArray<String> packages) { + synchronized (mMetadataLock) { + mLeasees.removeIf(leasee -> + !leasee.packageName.equals(packages.get(leasee.uid))); } } @@ -160,11 +187,18 @@ class BlobMetadata { return false; } + File getBlobFile() { + if (mBlobFile == null) { + mBlobFile = BlobStoreConfig.getBlobFile(blobId); + } + return mBlobFile; + } + ParcelFileDescriptor openForRead(String callingPackage) throws IOException { // TODO: Add limit on opened fds FileDescriptor fd; try { - fd = Os.open(BlobStoreConfig.getBlobFile(blobId).getPath(), O_RDONLY, 0); + fd = Os.open(getBlobFile().getPath(), O_RDONLY, 0); } catch (ErrnoException e) { throw e.rethrowAsIOException(); } 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 94f2eb19c926..fcc30e30dfaa 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java @@ -22,6 +22,10 @@ import static android.app.blob.XmlTags.TAG_BLOB; import static android.app.blob.XmlTags.TAG_BLOBS; import static android.app.blob.XmlTags.TAG_SESSION; import static android.app.blob.XmlTags.TAG_SESSIONS; +import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; +import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; +import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; +import static android.os.UserHandle.USER_NULL; import static com.android.server.blob.BlobStoreConfig.CURRENT_XML_VERSION; import static com.android.server.blob.BlobStoreConfig.TAG; @@ -39,7 +43,11 @@ import android.annotation.Nullable; import android.app.blob.BlobHandle; import android.app.blob.IBlobStoreManager; import android.app.blob.IBlobStoreSession; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManagerInternal; import android.os.Binder; import android.os.Handler; @@ -49,6 +57,7 @@ import android.os.Process; import android.os.RemoteCallback; import android.os.SystemClock; import android.os.UserHandle; +import android.os.UserManagerInternal; import android.util.ArrayMap; import android.util.AtomicFile; import android.util.ExceptionUtils; @@ -80,6 +89,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; /** * Service responsible for maintaining and facilitating access to data blobs published by apps. @@ -122,14 +133,16 @@ public class BlobStoreManagerService extends SystemService { publishBinderService(Context.BLOB_STORE_SERVICE, new Stub()); mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); + registerReceivers(); } @Override public void onBootPhase(int phase) { if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { synchronized (mBlobsLock) { - readBlobSessionsLocked(); - readBlobsInfoLocked(); + final SparseArray<SparseArray<String>> allPackages = getAllPackages(); + readBlobSessionsLocked(allPackages); + readBlobsInfoLocked(allPackages); } } } @@ -139,6 +152,15 @@ public class BlobStoreManagerService extends SystemService { return ++mCurrentMaxSessionId; } + private void registerReceivers() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); + intentFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); + intentFilter.addAction(Intent.ACTION_USER_REMOVED); + mContext.registerReceiverAsUser(new PackageChangedReceiver(), UserHandle.ALL, + intentFilter, null, mHandler); + } + @GuardedBy("mBlobsLock") private LongSparseArray<BlobStoreSession> getUserSessionsLocked(int userId) { LongSparseArray<BlobStoreSession> userSessions = mSessions.get(userId); @@ -349,11 +371,10 @@ public class BlobStoreManagerService extends SystemService { } @GuardedBy("mBlobsLock") - private void readBlobSessionsLocked() { + private void readBlobSessionsLocked(SparseArray<SparseArray<String>> allPackages) { if (!BlobStoreConfig.getBlobStoreRootDir().exists()) { return; } - final AtomicFile sessionsIndexFile = prepareSessionsIndexFile(); if (sessionsIndexFile == null) { Slog.wtf(TAG, "Error creating sessions index file"); @@ -377,8 +398,17 @@ public class BlobStoreManagerService extends SystemService { if (session == null) { continue; } - getUserSessionsLocked(UserHandle.getUserId(session.ownerUid)).put( - session.sessionId, session); + final SparseArray<String> userPackages = allPackages.get( + UserHandle.getUserId(session.ownerUid)); + if (userPackages != null + && session.ownerPackageName.equals( + userPackages.get(session.ownerUid))) { + getUserSessionsLocked(UserHandle.getUserId(session.ownerUid)).put( + session.sessionId, session); + } else { + // Unknown package or the session data does not belong to this package. + session.getSessionFile().delete(); + } mCurrentMaxSessionId = Math.max(mCurrentMaxSessionId, session.sessionId); } } @@ -423,11 +453,10 @@ public class BlobStoreManagerService extends SystemService { } @GuardedBy("mBlobsLock") - private void readBlobsInfoLocked() { + private void readBlobsInfoLocked(SparseArray<SparseArray<String>> allPackages) { if (!BlobStoreConfig.getBlobStoreRootDir().exists()) { return; } - final AtomicFile blobsIndexFile = prepareBlobsIndexFile(); if (blobsIndexFile == null) { Slog.wtf(TAG, "Error creating blobs index file"); @@ -447,8 +476,15 @@ public class BlobStoreManagerService extends SystemService { if (TAG_BLOB.equals(in.getName())) { final BlobMetadata blobMetadata = BlobMetadata.createFromXml(mContext, in); - getUserBlobsLocked(blobMetadata.userId).put( - blobMetadata.blobHandle, blobMetadata); + final SparseArray<String> userPackages = allPackages.get(blobMetadata.userId); + if (userPackages == null) { + blobMetadata.getBlobFile().delete(); + } else { + getUserBlobsLocked(blobMetadata.userId).put( + blobMetadata.blobHandle, blobMetadata); + blobMetadata.removeInvalidCommitters(userPackages); + blobMetadata.removeInvalidLeasees(userPackages); + } mCurrentMaxSessionId = Math.max(mCurrentMaxSessionId, blobMetadata.blobId); } } @@ -489,6 +525,33 @@ public class BlobStoreManagerService extends SystemService { BlobStoreManagerService.this).recycleOnUse()); } + private int getPackageUid(String packageName, int userId) { + final int uid = mPackageManagerInternal.getPackageUid( + packageName, + MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_UNINSTALLED_PACKAGES, + userId); + return uid; + } + + private SparseArray<SparseArray<String>> getAllPackages() { + final SparseArray<SparseArray<String>> allPackages = new SparseArray<>(); + final int[] allUsers = LocalServices.getService(UserManagerInternal.class).getUserIds(); + for (int userId : allUsers) { + final SparseArray<String> userPackages = new SparseArray<>(); + allPackages.put(userId, userPackages); + final List<ApplicationInfo> applicationInfos = mPackageManagerInternal + .getInstalledApplications( + MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE + | MATCH_UNINSTALLED_PACKAGES, + userId, Process.myUid()); + for (int i = 0, count = applicationInfos.size(); i < count; ++i) { + final ApplicationInfo applicationInfo = applicationInfos.get(i); + userPackages.put(applicationInfo.uid, applicationInfo.packageName); + } + } + return allPackages; + } + AtomicFile prepareSessionsIndexFile() { final File file = BlobStoreConfig.prepareSessionIndexFile(); if (file == null) { @@ -505,6 +568,91 @@ public class BlobStoreManagerService extends SystemService { return new AtomicFile(file, "blobs_index" /* commitLogTag */); } + private void handlePackageRemoved(String packageName, int uid) { + synchronized (mBlobsLock) { + // Clean up any pending sessions + final LongSparseArray<BlobStoreSession> userSessions = + getUserSessionsLocked(UserHandle.getUserId(uid)); + 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)) { + session.getSessionFile().delete(); + indicesToRemove.add(i); + } + } + for (int i = 0, count = indicesToRemove.size(); i < count; ++i) { + userSessions.removeAt(i); + } + + // Remove the package from the committer and leasee list + final ArrayMap<BlobHandle, BlobMetadata> userBlobs = + getUserBlobsLocked(UserHandle.getUserId(uid)); + for (int i = 0, count = userBlobs.size(); i < count; ++i) { + final BlobMetadata blobMetadata = userBlobs.valueAt(i); + blobMetadata.removeCommitter(packageName, uid); + blobMetadata.removeLeasee(packageName, uid); + } + // TODO: clean-up blobs which doesn't have any active leases. + } + } + + private void handleUserRemoved(int userId) { + synchronized (mBlobsLock) { + final LongSparseArray<BlobStoreSession> userSessions = + mSessions.removeReturnOld(userId); + if (userSessions != null) { + for (int i = 0, count = userSessions.size(); i < count; ++i) { + final BlobStoreSession session = userSessions.valueAt(i); + session.getSessionFile().delete(); + } + } + + final ArrayMap<BlobHandle, BlobMetadata> userBlobs = + mBlobsMap.removeReturnOld(userId); + if (userBlobs != null) { + for (int i = 0, count = userBlobs.size(); i < count; ++i) { + final BlobMetadata blobMetadata = userBlobs.valueAt(i); + blobMetadata.getBlobFile().delete(); + } + } + } + } + + private class PackageChangedReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + switch (intent.getAction()) { + case Intent.ACTION_PACKAGE_FULLY_REMOVED: + case Intent.ACTION_PACKAGE_DATA_CLEARED: + final String packageName = intent.getData().getSchemeSpecificPart(); + if (packageName == null) { + Slog.wtf(TAG, "Package name is missing in the intent: " + intent); + return; + } + final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); + if (uid == -1) { + Slog.wtf(TAG, "uid is missing in the intent: " + intent); + return; + } + handlePackageRemoved(packageName, uid); + break; + case Intent.ACTION_USER_REMOVED: + final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, + USER_NULL); + if (userId == USER_NULL) { + Slog.wtf(TAG, "userId is missing in the intent: " + intent); + return; + } + handleUserRemoved(userId); + break; + default: + Slog.wtf(TAG, "Received unknown intent: " + intent); + } + } + } + private class Stub extends IBlobStoreManager.Stub { @Override @IntRange(from = 1) @@ -622,6 +770,8 @@ public class BlobStoreManagerService extends SystemService { 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); |