summaryrefslogtreecommitdiff
path: root/apex/blobstore
diff options
context:
space:
mode:
authorSudheer Shanka <sudheersai@google.com>2020-01-21 13:32:04 -0800
committerSudheer Shanka <sudheersai@google.com>2020-01-23 18:02:20 -0800
commit22f0b166e89b7b8ad8e82a4e2dd359e692e0ae84 (patch)
treebc460c431a0496fdd8f9f30780adfcf385b0017b /apex/blobstore
parentf6e23b96b5f289a4c6dd4884288e2eeb42713270 (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.java38
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java170
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);