diff options
Diffstat (limited to 'apex/blobstore')
-rw-r--r-- | apex/blobstore/framework/java/android/app/blob/BlobInfo.java | 16 | ||||
-rw-r--r-- | apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java | 45 | ||||
-rw-r--r-- | apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl | 4 | ||||
-rw-r--r-- | apex/blobstore/framework/java/android/app/blob/LeaseInfo.aidl | 19 | ||||
-rw-r--r-- | apex/blobstore/framework/java/android/app/blob/LeaseInfo.java (renamed from apex/blobstore/framework/java/android/app/blob/AccessorInfo.java) | 53 | ||||
-rw-r--r-- | apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java | 20 | ||||
-rw-r--r-- | apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java | 75 | ||||
-rw-r--r-- | apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java | 9 |
8 files changed, 208 insertions, 33 deletions
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobInfo.java b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java index 9746dd023002..80062d5d245f 100644 --- a/apex/blobstore/framework/java/android/app/blob/BlobInfo.java +++ b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java @@ -32,21 +32,21 @@ public final class BlobInfo implements Parcelable { private final long mId; private final long mExpiryTimeMs; private final CharSequence mLabel; - private final List<AccessorInfo> mAccessors; + private final List<LeaseInfo> mLeaseInfos; public BlobInfo(long id, long expiryTimeMs, CharSequence label, - List<AccessorInfo> accessors) { + List<LeaseInfo> leaseInfos) { mId = id; mExpiryTimeMs = expiryTimeMs; mLabel = label; - mAccessors = accessors; + mLeaseInfos = leaseInfos; } private BlobInfo(Parcel in) { mId = in.readLong(); mExpiryTimeMs = in.readLong(); mLabel = in.readCharSequence(); - mAccessors = in.readArrayList(null /* classloader */); + mLeaseInfos = in.readArrayList(null /* classloader */); } public long getId() { @@ -61,8 +61,8 @@ public final class BlobInfo implements Parcelable { return mLabel; } - public List<AccessorInfo> getAccessors() { - return Collections.unmodifiableList(mAccessors); + public List<LeaseInfo> getLeases() { + return Collections.unmodifiableList(mLeaseInfos); } @Override @@ -70,7 +70,7 @@ public final class BlobInfo implements Parcelable { dest.writeLong(mId); dest.writeLong(mExpiryTimeMs); dest.writeCharSequence(mLabel); - dest.writeList(mAccessors); + dest.writeList(mLeaseInfos); } @Override @@ -83,7 +83,7 @@ public final class BlobInfo implements Parcelable { + "id: " + mId + "," + "expiryMs: " + mExpiryTimeMs + "," + "label: " + mLabel + "," - + "accessors: " + AccessorInfo.toShortString(mAccessors) + "," + + "leases: " + LeaseInfo.toShortString(mLeaseInfos) + "," + "}"; } diff --git a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java index 814ab6dbd7fd..c339351759cd 100644 --- a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java +++ b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java @@ -21,6 +21,7 @@ import android.annotation.CurrentTimeMillisLong; import android.annotation.IdRes; import android.annotation.IntRange; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemService; import android.annotation.TestApi; import android.content.Context; @@ -522,6 +523,50 @@ public class BlobStoreManager { } /** + * Return the {@link BlobHandle BlobHandles} corresponding to the data blobs that + * the calling app has acquired a lease on using {@link #acquireLease(BlobHandle, int)} or + * one of it's other variants. + * + * @hide + */ + @TestApi + @NonNull + public List<BlobHandle> getLeasedBlobs() throws IOException { + try { + return mService.getLeasedBlobs(mContext.getOpPackageName()); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Return {@link LeaseInfo} representing a lease acquired using + * {@link #acquireLease(BlobHandle, int)} or one of it's other variants, + * or {@code null} if there is no lease acquired. + * + * @throws SecurityException when the blob represented by the {@code blobHandle} does not + * exist or the caller does not have access to it. + * @throws IllegalArgumentException when {@code blobHandle} is invalid. + * + * @hide + */ + @TestApi + @Nullable + public LeaseInfo getLeaseInfo(@NonNull BlobHandle blobHandle) throws IOException { + try { + return mService.getLeaseInfo(blobHandle, mContext.getOpPackageName()); + } catch (ParcelableException e) { + e.maybeRethrow(IOException.class); + throw new RuntimeException(e); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Represents an ongoing session of a blob's contribution to the blob store managed by the * system. * diff --git a/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl b/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl index e78381359b41..20c15ab57496 100644 --- a/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl +++ b/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl @@ -18,6 +18,7 @@ package android.app.blob; import android.app.blob.BlobHandle; import android.app.blob.BlobInfo; import android.app.blob.IBlobStoreSession; +import android.app.blob.LeaseInfo; import android.os.RemoteCallback; /** {@hide} */ @@ -35,4 +36,7 @@ interface IBlobStoreManager { List<BlobInfo> queryBlobsForUser(int userId); void deleteBlob(long blobId); + + List<BlobHandle> getLeasedBlobs(in String packageName); + LeaseInfo getLeaseInfo(in BlobHandle blobHandle, in String packageName); }
\ No newline at end of file diff --git a/apex/blobstore/framework/java/android/app/blob/LeaseInfo.aidl b/apex/blobstore/framework/java/android/app/blob/LeaseInfo.aidl new file mode 100644 index 000000000000..908885731bb1 --- /dev/null +++ b/apex/blobstore/framework/java/android/app/blob/LeaseInfo.aidl @@ -0,0 +1,19 @@ +/* + * 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 android.app.blob; + +/** {@hide} */ +parcelable LeaseInfo;
\ No newline at end of file diff --git a/apex/blobstore/framework/java/android/app/blob/AccessorInfo.java b/apex/blobstore/framework/java/android/app/blob/LeaseInfo.java index 3725ad4a6c09..fef50c9e8dba 100644 --- a/apex/blobstore/framework/java/android/app/blob/AccessorInfo.java +++ b/apex/blobstore/framework/java/android/app/blob/LeaseInfo.java @@ -16,50 +16,61 @@ package android.app.blob; +import android.annotation.CurrentTimeMillisLong; +import android.annotation.IdRes; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; import java.util.List; /** - * Class to provide information about an accessor of a shared blob. + * Class to provide information about a lease (acquired using + * {@link BlobStoreManager#acquireLease(BlobHandle, int)} or one of it's variants) + * for a shared blob. * * @hide */ -public final class AccessorInfo implements Parcelable { +@TestApi +public final class LeaseInfo implements Parcelable { private final String mPackageName; - private final long mExpiryTimeMs; + private final long mExpiryTimeMillis; private final int mDescriptionResId; private final CharSequence mDescription; - public AccessorInfo(String packageName, long expiryTimeMs, - int descriptionResId, CharSequence description) { + public LeaseInfo(@NonNull String packageName, @CurrentTimeMillisLong long expiryTimeMs, + @IdRes int descriptionResId, @Nullable CharSequence description) { mPackageName = packageName; - mExpiryTimeMs = expiryTimeMs; + mExpiryTimeMillis = expiryTimeMs; mDescriptionResId = descriptionResId; mDescription = description; } - private AccessorInfo(Parcel in) { + private LeaseInfo(Parcel in) { mPackageName = in.readString(); - mExpiryTimeMs = in.readLong(); + mExpiryTimeMillis = in.readLong(); mDescriptionResId = in.readInt(); mDescription = in.readCharSequence(); } + @NonNull public String getPackageName() { return mPackageName; } - public long getExpiryTimeMs() { - return mExpiryTimeMs; + @CurrentTimeMillisLong + public long getExpiryTimeMillis() { + return mExpiryTimeMillis; } + @IdRes public int getDescriptionResId() { return mDescriptionResId; } + @Nullable public CharSequence getDescription() { return mDescription; } @@ -67,16 +78,16 @@ public final class AccessorInfo implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString(mPackageName); - dest.writeLong(mExpiryTimeMs); + dest.writeLong(mExpiryTimeMillis); dest.writeInt(mDescriptionResId); dest.writeCharSequence(mDescription); } @Override public String toString() { - return "AccessorInfo {" + return "LeaseInfo {" + "package: " + mPackageName + "," - + "expiryMs: " + mExpiryTimeMs + "," + + "expiryMs: " + mExpiryTimeMillis + "," + "descriptionResId: " + mDescriptionResId + "," + "description: " + mDescription + "," + "}"; @@ -86,11 +97,11 @@ public final class AccessorInfo implements Parcelable { return mPackageName; } - public static String toShortString(List<AccessorInfo> accessors) { + static String toShortString(List<LeaseInfo> leaseInfos) { final StringBuilder sb = new StringBuilder(); sb.append("["); - for (int i = 0, size = accessors.size(); i < size; ++i) { - sb.append(accessors.get(i).toShortString()); + for (int i = 0, size = leaseInfos.size(); i < size; ++i) { + sb.append(leaseInfos.get(i).toShortString()); sb.append(","); } sb.append("]"); @@ -103,17 +114,17 @@ public final class AccessorInfo implements Parcelable { } @NonNull - public static final Creator<AccessorInfo> CREATOR = new Creator<AccessorInfo>() { + public static final Creator<LeaseInfo> CREATOR = new Creator<LeaseInfo>() { @Override @NonNull - public AccessorInfo createFromParcel(Parcel source) { - return new AccessorInfo(source); + public LeaseInfo createFromParcel(Parcel source) { + return new LeaseInfo(source); } @Override @NonNull - public AccessorInfo[] newArray(int size) { - return new AccessorInfo[size]; + public LeaseInfo[] newArray(int size) { + return new LeaseInfo[size]; } }; } 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 970766d2c8a6..8b640ca75698 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java @@ -38,6 +38,7 @@ import static com.android.server.blob.BlobStoreUtils.getPackageResources; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.blob.BlobHandle; +import android.app.blob.LeaseInfo; import android.content.Context; import android.content.res.ResourceId; import android.content.res.Resources; @@ -281,6 +282,25 @@ class BlobMetadata { return false; } + @Nullable + LeaseInfo getLeaseInfo(@NonNull String packageName, int uid) { + synchronized (mMetadataLock) { + for (int i = 0, size = mLeasees.size(); i < size; ++i) { + final Leasee leasee = mLeasees.valueAt(i); + if (leasee.uid == uid && leasee.packageName.equals(packageName)) { + final int descriptionResId = leasee.descriptionResEntryName == null + ? Resources.ID_NULL + : BlobStoreUtils.getDescriptionResourceId( + mContext, leasee.descriptionResEntryName, leasee.packageName, + UserHandle.getUserId(leasee.uid)); + return new LeaseInfo(packageName, leasee.expiryTimeMillis, + descriptionResId, leasee.description); + } + } + } + return null; + } + void forEachLeasee(Consumer<Leasee> consumer) { mLeasees.forEach(consumer); } 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 53a97cefa59b..f4b8f0f39e85 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java @@ -45,11 +45,11 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; -import android.app.blob.AccessorInfo; import android.app.blob.BlobHandle; import android.app.blob.BlobInfo; import android.app.blob.IBlobStoreManager; import android.app.blob.IBlobStoreSession; +import android.app.blob.LeaseInfo; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -454,17 +454,17 @@ public class BlobStoreManagerService extends SystemService { return packageResources; }; getUserBlobsLocked(userId).forEach((blobHandle, blobMetadata) -> { - final ArrayList<AccessorInfo> accessorInfos = new ArrayList<>(); + final ArrayList<LeaseInfo> leaseInfos = new ArrayList<>(); blobMetadata.forEachLeasee(leasee -> { final int descriptionResId = leasee.descriptionResEntryName == null ? Resources.ID_NULL : getDescriptionResourceId(resourcesGetter.apply(leasee.packageName), leasee.descriptionResEntryName, leasee.packageName); - accessorInfos.add(new AccessorInfo(leasee.packageName, leasee.expiryTimeMillis, + leaseInfos.add(new LeaseInfo(leasee.packageName, leasee.expiryTimeMillis, descriptionResId, leasee.description)); }); blobInfos.add(new BlobInfo(blobMetadata.getBlobId(), - blobHandle.getExpiryTimeMillis(), blobHandle.getLabel(), accessorInfos)); + blobHandle.getExpiryTimeMillis(), blobHandle.getLabel(), leaseInfos)); }); } return blobInfos; @@ -482,6 +482,31 @@ public class BlobStoreManagerService extends SystemService { } } + private List<BlobHandle> getLeasedBlobsInternal(int callingUid, + @NonNull String callingPackage) { + final ArrayList<BlobHandle> leasedBlobs = new ArrayList<>(); + forEachBlobInUser(blobMetadata -> { + if (blobMetadata.isALeasee(callingPackage, callingUid)) { + leasedBlobs.add(blobMetadata.getBlobHandle()); + } + }, UserHandle.getUserId(callingUid)); + return leasedBlobs; + } + + private LeaseInfo getLeaseInfoInternal(BlobHandle blobHandle, + int callingUid, @NonNull String callingPackage) { + synchronized (mBlobsLock) { + final BlobMetadata blobMetadata = getUserBlobsLocked(UserHandle.getUserId(callingUid)) + .get(blobHandle); + if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller( + callingPackage, callingUid)) { + throw new SecurityException("Caller not allowed to access " + blobHandle + + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage); + } + return blobMetadata.getLeaseInfo(callingPackage, callingUid); + } + } + private void verifyCallingPackage(int callingUid, String callingPackage) { if (mPackageManagerInternal.getPackageUid( callingPackage, 0, UserHandle.getUserId(callingUid)) != callingUid) { @@ -1267,6 +1292,12 @@ public class BlobStoreManagerService extends SystemService { final int callingUid = Binder.getCallingUid(); verifyCallingPackage(callingUid, packageName); + if (Process.isIsolated(callingUid) || mPackageManagerInternal.isInstantApp( + packageName, UserHandle.getUserId(callingUid))) { + throw new SecurityException("Caller not allowed to open blob; " + + "callingUid=" + callingUid + ", callingPackage=" + packageName); + } + try { acquireLeaseInternal(blobHandle, descriptionResId, description, leaseExpiryTimeMillis, callingUid, packageName); @@ -1284,6 +1315,12 @@ public class BlobStoreManagerService extends SystemService { final int callingUid = Binder.getCallingUid(); verifyCallingPackage(callingUid, packageName); + if (Process.isIsolated(callingUid) || mPackageManagerInternal.isInstantApp( + packageName, UserHandle.getUserId(callingUid))) { + throw new SecurityException("Caller not allowed to open blob; " + + "callingUid=" + callingUid + ", callingPackage=" + packageName); + } + releaseLeaseInternal(blobHandle, callingUid, packageName); } @@ -1320,6 +1357,36 @@ public class BlobStoreManagerService extends SystemService { } @Override + @NonNull + public List<BlobHandle> getLeasedBlobs(@NonNull String packageName) { + Objects.requireNonNull(packageName, "packageName must not be null"); + + final int callingUid = Binder.getCallingUid(); + verifyCallingPackage(callingUid, packageName); + + return getLeasedBlobsInternal(callingUid, packageName); + } + + @Override + @Nullable + public LeaseInfo getLeaseInfo(@NonNull BlobHandle blobHandle, @NonNull String packageName) { + 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); + + if (Process.isIsolated(callingUid) || mPackageManagerInternal.isInstantApp( + packageName, UserHandle.getUserId(callingUid))) { + throw new SecurityException("Caller not allowed to open blob; " + + "callingUid=" + callingUid + ", callingPackage=" + packageName); + } + + return getLeaseInfoInternal(blobHandle, callingUid, packageName); + } + + @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) { // TODO: add proto-based version of this. diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java index 6af540acd6a4..fabce766c237 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java @@ -47,4 +47,13 @@ class BlobStoreUtils { @NonNull String resourceEntryName, @NonNull String packageName) { return resources.getIdentifier(resourceEntryName, DESC_RES_TYPE_STRING, packageName); } + + @IdRes + static int getDescriptionResourceId(@NonNull Context context, + @NonNull String resourceEntryName, @NonNull String packageName, int userId) { + final Resources resources = getPackageResources(context, packageName, userId); + return resources == null + ? Resources.ID_NULL + : getDescriptionResourceId(resources, resourceEntryName, packageName); + } } |