Merge "Add @TestApis getLeasedBlobs() and getLeaseInfo()." into rvc-dev am: c95e8472c4 am: 188abab52a am: 59b86e4341
Change-Id: Ia4b58e165b183089fd09205ce95a86b40732eb83
This commit is contained in:
@@ -121,8 +121,9 @@ public class BlobStorePerfTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private DummyBlobData prepareDataBlob(int fileSizeInMb) throws Exception {
|
private DummyBlobData prepareDataBlob(int fileSizeInMb) throws Exception {
|
||||||
final DummyBlobData blobData = new DummyBlobData(mContext,
|
final DummyBlobData blobData = new DummyBlobData.Builder(mContext)
|
||||||
fileSizeInMb * 1024 * 1024 /* bytes */);
|
.setFileSize(fileSizeInMb * 1024 * 1024 /* bytes */)
|
||||||
|
.build();
|
||||||
blobData.prepare();
|
blobData.prepare();
|
||||||
return blobData;
|
return blobData;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,21 +32,21 @@ public final class BlobInfo implements Parcelable {
|
|||||||
private final long mId;
|
private final long mId;
|
||||||
private final long mExpiryTimeMs;
|
private final long mExpiryTimeMs;
|
||||||
private final CharSequence mLabel;
|
private final CharSequence mLabel;
|
||||||
private final List<AccessorInfo> mAccessors;
|
private final List<LeaseInfo> mLeaseInfos;
|
||||||
|
|
||||||
public BlobInfo(long id, long expiryTimeMs, CharSequence label,
|
public BlobInfo(long id, long expiryTimeMs, CharSequence label,
|
||||||
List<AccessorInfo> accessors) {
|
List<LeaseInfo> leaseInfos) {
|
||||||
mId = id;
|
mId = id;
|
||||||
mExpiryTimeMs = expiryTimeMs;
|
mExpiryTimeMs = expiryTimeMs;
|
||||||
mLabel = label;
|
mLabel = label;
|
||||||
mAccessors = accessors;
|
mLeaseInfos = leaseInfos;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BlobInfo(Parcel in) {
|
private BlobInfo(Parcel in) {
|
||||||
mId = in.readLong();
|
mId = in.readLong();
|
||||||
mExpiryTimeMs = in.readLong();
|
mExpiryTimeMs = in.readLong();
|
||||||
mLabel = in.readCharSequence();
|
mLabel = in.readCharSequence();
|
||||||
mAccessors = in.readArrayList(null /* classloader */);
|
mLeaseInfos = in.readArrayList(null /* classloader */);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getId() {
|
public long getId() {
|
||||||
@@ -61,8 +61,8 @@ public final class BlobInfo implements Parcelable {
|
|||||||
return mLabel;
|
return mLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<AccessorInfo> getAccessors() {
|
public List<LeaseInfo> getLeases() {
|
||||||
return Collections.unmodifiableList(mAccessors);
|
return Collections.unmodifiableList(mLeaseInfos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -70,7 +70,7 @@ public final class BlobInfo implements Parcelable {
|
|||||||
dest.writeLong(mId);
|
dest.writeLong(mId);
|
||||||
dest.writeLong(mExpiryTimeMs);
|
dest.writeLong(mExpiryTimeMs);
|
||||||
dest.writeCharSequence(mLabel);
|
dest.writeCharSequence(mLabel);
|
||||||
dest.writeList(mAccessors);
|
dest.writeList(mLeaseInfos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -83,7 +83,7 @@ public final class BlobInfo implements Parcelable {
|
|||||||
+ "id: " + mId + ","
|
+ "id: " + mId + ","
|
||||||
+ "expiryMs: " + mExpiryTimeMs + ","
|
+ "expiryMs: " + mExpiryTimeMs + ","
|
||||||
+ "label: " + mLabel + ","
|
+ "label: " + mLabel + ","
|
||||||
+ "accessors: " + AccessorInfo.toShortString(mAccessors) + ","
|
+ "leases: " + LeaseInfo.toShortString(mLeaseInfos) + ","
|
||||||
+ "}";
|
+ "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import android.annotation.CurrentTimeMillisLong;
|
|||||||
import android.annotation.IdRes;
|
import android.annotation.IdRes;
|
||||||
import android.annotation.IntRange;
|
import android.annotation.IntRange;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.annotation.SystemService;
|
import android.annotation.SystemService;
|
||||||
import android.annotation.TestApi;
|
import android.annotation.TestApi;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -521,6 +522,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
|
* Represents an ongoing session of a blob's contribution to the blob store managed by the
|
||||||
* system.
|
* system.
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package android.app.blob;
|
|||||||
import android.app.blob.BlobHandle;
|
import android.app.blob.BlobHandle;
|
||||||
import android.app.blob.BlobInfo;
|
import android.app.blob.BlobInfo;
|
||||||
import android.app.blob.IBlobStoreSession;
|
import android.app.blob.IBlobStoreSession;
|
||||||
|
import android.app.blob.LeaseInfo;
|
||||||
import android.os.RemoteCallback;
|
import android.os.RemoteCallback;
|
||||||
|
|
||||||
/** {@hide} */
|
/** {@hide} */
|
||||||
@@ -35,4 +36,7 @@ interface IBlobStoreManager {
|
|||||||
|
|
||||||
List<BlobInfo> queryBlobsForUser(int userId);
|
List<BlobInfo> queryBlobsForUser(int userId);
|
||||||
void deleteBlob(long blobId);
|
void deleteBlob(long blobId);
|
||||||
|
|
||||||
|
List<BlobHandle> getLeasedBlobs(in String packageName);
|
||||||
|
LeaseInfo getLeaseInfo(in BlobHandle blobHandle, in String packageName);
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
@@ -16,50 +16,61 @@
|
|||||||
|
|
||||||
package android.app.blob;
|
package android.app.blob;
|
||||||
|
|
||||||
|
import android.annotation.CurrentTimeMillisLong;
|
||||||
|
import android.annotation.IdRes;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.annotation.TestApi;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
import java.util.List;
|
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
|
* @hide
|
||||||
*/
|
*/
|
||||||
public final class AccessorInfo implements Parcelable {
|
@TestApi
|
||||||
|
public final class LeaseInfo implements Parcelable {
|
||||||
private final String mPackageName;
|
private final String mPackageName;
|
||||||
private final long mExpiryTimeMs;
|
private final long mExpiryTimeMillis;
|
||||||
private final int mDescriptionResId;
|
private final int mDescriptionResId;
|
||||||
private final CharSequence mDescription;
|
private final CharSequence mDescription;
|
||||||
|
|
||||||
public AccessorInfo(String packageName, long expiryTimeMs,
|
public LeaseInfo(@NonNull String packageName, @CurrentTimeMillisLong long expiryTimeMs,
|
||||||
int descriptionResId, CharSequence description) {
|
@IdRes int descriptionResId, @Nullable CharSequence description) {
|
||||||
mPackageName = packageName;
|
mPackageName = packageName;
|
||||||
mExpiryTimeMs = expiryTimeMs;
|
mExpiryTimeMillis = expiryTimeMs;
|
||||||
mDescriptionResId = descriptionResId;
|
mDescriptionResId = descriptionResId;
|
||||||
mDescription = description;
|
mDescription = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AccessorInfo(Parcel in) {
|
private LeaseInfo(Parcel in) {
|
||||||
mPackageName = in.readString();
|
mPackageName = in.readString();
|
||||||
mExpiryTimeMs = in.readLong();
|
mExpiryTimeMillis = in.readLong();
|
||||||
mDescriptionResId = in.readInt();
|
mDescriptionResId = in.readInt();
|
||||||
mDescription = in.readCharSequence();
|
mDescription = in.readCharSequence();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
public String getPackageName() {
|
public String getPackageName() {
|
||||||
return mPackageName;
|
return mPackageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getExpiryTimeMs() {
|
@CurrentTimeMillisLong
|
||||||
return mExpiryTimeMs;
|
public long getExpiryTimeMillis() {
|
||||||
|
return mExpiryTimeMillis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@IdRes
|
||||||
public int getDescriptionResId() {
|
public int getDescriptionResId() {
|
||||||
return mDescriptionResId;
|
return mDescriptionResId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public CharSequence getDescription() {
|
public CharSequence getDescription() {
|
||||||
return mDescription;
|
return mDescription;
|
||||||
}
|
}
|
||||||
@@ -67,16 +78,16 @@ public final class AccessorInfo implements Parcelable {
|
|||||||
@Override
|
@Override
|
||||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||||
dest.writeString(mPackageName);
|
dest.writeString(mPackageName);
|
||||||
dest.writeLong(mExpiryTimeMs);
|
dest.writeLong(mExpiryTimeMillis);
|
||||||
dest.writeInt(mDescriptionResId);
|
dest.writeInt(mDescriptionResId);
|
||||||
dest.writeCharSequence(mDescription);
|
dest.writeCharSequence(mDescription);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "AccessorInfo {"
|
return "LeaseInfo {"
|
||||||
+ "package: " + mPackageName + ","
|
+ "package: " + mPackageName + ","
|
||||||
+ "expiryMs: " + mExpiryTimeMs + ","
|
+ "expiryMs: " + mExpiryTimeMillis + ","
|
||||||
+ "descriptionResId: " + mDescriptionResId + ","
|
+ "descriptionResId: " + mDescriptionResId + ","
|
||||||
+ "description: " + mDescription + ","
|
+ "description: " + mDescription + ","
|
||||||
+ "}";
|
+ "}";
|
||||||
@@ -86,11 +97,11 @@ public final class AccessorInfo implements Parcelable {
|
|||||||
return mPackageName;
|
return mPackageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String toShortString(List<AccessorInfo> accessors) {
|
static String toShortString(List<LeaseInfo> leaseInfos) {
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
sb.append("[");
|
sb.append("[");
|
||||||
for (int i = 0, size = accessors.size(); i < size; ++i) {
|
for (int i = 0, size = leaseInfos.size(); i < size; ++i) {
|
||||||
sb.append(accessors.get(i).toShortString());
|
sb.append(leaseInfos.get(i).toShortString());
|
||||||
sb.append(",");
|
sb.append(",");
|
||||||
}
|
}
|
||||||
sb.append("]");
|
sb.append("]");
|
||||||
@@ -103,17 +114,17 @@ public final class AccessorInfo implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static final Creator<AccessorInfo> CREATOR = new Creator<AccessorInfo>() {
|
public static final Creator<LeaseInfo> CREATOR = new Creator<LeaseInfo>() {
|
||||||
@Override
|
@Override
|
||||||
@NonNull
|
@NonNull
|
||||||
public AccessorInfo createFromParcel(Parcel source) {
|
public LeaseInfo createFromParcel(Parcel source) {
|
||||||
return new AccessorInfo(source);
|
return new LeaseInfo(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NonNull
|
@NonNull
|
||||||
public AccessorInfo[] newArray(int size) {
|
public LeaseInfo[] newArray(int size) {
|
||||||
return new AccessorInfo[size];
|
return new LeaseInfo[size];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -38,6 +38,7 @@ import static com.android.server.blob.BlobStoreUtils.getPackageResources;
|
|||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.app.blob.BlobHandle;
|
import android.app.blob.BlobHandle;
|
||||||
|
import android.app.blob.LeaseInfo;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.ResourceId;
|
import android.content.res.ResourceId;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
@@ -281,6 +282,25 @@ class BlobMetadata {
|
|||||||
return false;
|
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) {
|
void forEachLeasee(Consumer<Leasee> consumer) {
|
||||||
mLeasees.forEach(consumer);
|
mLeasees.forEach(consumer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,11 +45,11 @@ import android.annotation.IntRange;
|
|||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.annotation.UserIdInt;
|
import android.annotation.UserIdInt;
|
||||||
import android.app.blob.AccessorInfo;
|
|
||||||
import android.app.blob.BlobHandle;
|
import android.app.blob.BlobHandle;
|
||||||
import android.app.blob.BlobInfo;
|
import android.app.blob.BlobInfo;
|
||||||
import android.app.blob.IBlobStoreManager;
|
import android.app.blob.IBlobStoreManager;
|
||||||
import android.app.blob.IBlobStoreSession;
|
import android.app.blob.IBlobStoreSession;
|
||||||
|
import android.app.blob.LeaseInfo;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -454,17 +454,17 @@ public class BlobStoreManagerService extends SystemService {
|
|||||||
return packageResources;
|
return packageResources;
|
||||||
};
|
};
|
||||||
getUserBlobsLocked(userId).forEach((blobHandle, blobMetadata) -> {
|
getUserBlobsLocked(userId).forEach((blobHandle, blobMetadata) -> {
|
||||||
final ArrayList<AccessorInfo> accessorInfos = new ArrayList<>();
|
final ArrayList<LeaseInfo> leaseInfos = new ArrayList<>();
|
||||||
blobMetadata.forEachLeasee(leasee -> {
|
blobMetadata.forEachLeasee(leasee -> {
|
||||||
final int descriptionResId = leasee.descriptionResEntryName == null
|
final int descriptionResId = leasee.descriptionResEntryName == null
|
||||||
? Resources.ID_NULL
|
? Resources.ID_NULL
|
||||||
: getDescriptionResourceId(resourcesGetter.apply(leasee.packageName),
|
: getDescriptionResourceId(resourcesGetter.apply(leasee.packageName),
|
||||||
leasee.descriptionResEntryName, 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));
|
descriptionResId, leasee.description));
|
||||||
});
|
});
|
||||||
blobInfos.add(new BlobInfo(blobMetadata.getBlobId(),
|
blobInfos.add(new BlobInfo(blobMetadata.getBlobId(),
|
||||||
blobHandle.getExpiryTimeMillis(), blobHandle.getLabel(), accessorInfos));
|
blobHandle.getExpiryTimeMillis(), blobHandle.getLabel(), leaseInfos));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return blobInfos;
|
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) {
|
private void verifyCallingPackage(int callingUid, String callingPackage) {
|
||||||
if (mPackageManagerInternal.getPackageUid(
|
if (mPackageManagerInternal.getPackageUid(
|
||||||
callingPackage, 0, UserHandle.getUserId(callingUid)) != callingUid) {
|
callingPackage, 0, UserHandle.getUserId(callingUid)) != callingUid) {
|
||||||
@@ -1267,6 +1292,12 @@ public class BlobStoreManagerService extends SystemService {
|
|||||||
final int callingUid = Binder.getCallingUid();
|
final int callingUid = Binder.getCallingUid();
|
||||||
verifyCallingPackage(callingUid, packageName);
|
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 {
|
try {
|
||||||
acquireLeaseInternal(blobHandle, descriptionResId, description,
|
acquireLeaseInternal(blobHandle, descriptionResId, description,
|
||||||
leaseExpiryTimeMillis, callingUid, packageName);
|
leaseExpiryTimeMillis, callingUid, packageName);
|
||||||
@@ -1284,6 +1315,12 @@ public class BlobStoreManagerService extends SystemService {
|
|||||||
final int callingUid = Binder.getCallingUid();
|
final int callingUid = Binder.getCallingUid();
|
||||||
verifyCallingPackage(callingUid, packageName);
|
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);
|
releaseLeaseInternal(blobHandle, callingUid, packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1319,6 +1356,36 @@ public class BlobStoreManagerService extends SystemService {
|
|||||||
deleteBlobInternal(blobId, callingUid);
|
deleteBlobInternal(blobId, callingUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Override
|
||||||
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
|
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
|
||||||
@Nullable String[] args) {
|
@Nullable String[] args) {
|
||||||
|
|||||||
@@ -47,4 +47,13 @@ class BlobStoreUtils {
|
|||||||
@NonNull String resourceEntryName, @NonNull String packageName) {
|
@NonNull String resourceEntryName, @NonNull String packageName) {
|
||||||
return resources.getIdentifier(resourceEntryName, DESC_RES_TYPE_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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -597,9 +597,22 @@ package android.app.backup {
|
|||||||
package android.app.blob {
|
package android.app.blob {
|
||||||
|
|
||||||
public class BlobStoreManager {
|
public class BlobStoreManager {
|
||||||
|
method @Nullable public android.app.blob.LeaseInfo getLeaseInfo(@NonNull android.app.blob.BlobHandle) throws java.io.IOException;
|
||||||
|
method @NonNull public java.util.List<android.app.blob.BlobHandle> getLeasedBlobs() throws java.io.IOException;
|
||||||
method public void waitForIdle(long) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
|
method public void waitForIdle(long) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class LeaseInfo implements android.os.Parcelable {
|
||||||
|
ctor public LeaseInfo(@NonNull String, long, @IdRes int, @Nullable CharSequence);
|
||||||
|
method public int describeContents();
|
||||||
|
method @Nullable public CharSequence getDescription();
|
||||||
|
method @IdRes public int getDescriptionResId();
|
||||||
|
method public long getExpiryTimeMillis();
|
||||||
|
method @NonNull public String getPackageName();
|
||||||
|
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||||
|
field @NonNull public static final android.os.Parcelable.Creator<android.app.blob.LeaseInfo> CREATOR;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
package android.app.prediction {
|
package android.app.prediction {
|
||||||
|
|||||||
@@ -38,38 +38,75 @@ import java.util.concurrent.TimeUnit;
|
|||||||
public class DummyBlobData {
|
public class DummyBlobData {
|
||||||
private static final long DEFAULT_SIZE_BYTES = 10 * 1024L * 1024L;
|
private static final long DEFAULT_SIZE_BYTES = 10 * 1024L * 1024L;
|
||||||
|
|
||||||
private final Context mContext;
|
|
||||||
private final Random mRandom;
|
private final Random mRandom;
|
||||||
private final File mFile;
|
private final File mFile;
|
||||||
private final long mFileSize;
|
private final long mFileSize;
|
||||||
private final String mLabel;
|
private final CharSequence mLabel;
|
||||||
|
|
||||||
byte[] mFileDigest;
|
byte[] mFileDigest;
|
||||||
long mExpiryTimeMs;
|
long mExpiryTimeMs;
|
||||||
|
|
||||||
public DummyBlobData(Context context) {
|
public DummyBlobData(Builder builder) {
|
||||||
this(context, new Random(0), "blob_" + System.nanoTime());
|
mRandom = new Random(builder.getRandomSeed());
|
||||||
|
mFile = new File(builder.getContext().getFilesDir(), builder.getFileName());
|
||||||
|
mFileSize = builder.getFileSize();
|
||||||
|
mLabel = builder.getLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DummyBlobData(Context context, long fileSize) {
|
public static class Builder {
|
||||||
this(context, fileSize, new Random(0), "blob_" + System.nanoTime(), "Test label");
|
private final Context mContext;
|
||||||
}
|
private int mRandomSeed = 0;
|
||||||
|
private long mFileSize = DEFAULT_SIZE_BYTES;
|
||||||
|
private CharSequence mLabel = "Test label";
|
||||||
|
private String mFileName = "blob_" + System.nanoTime();
|
||||||
|
|
||||||
public DummyBlobData(Context context, Random random, String fileName) {
|
public Builder(Context context) {
|
||||||
this(context, DEFAULT_SIZE_BYTES, random, fileName, "Test label");
|
mContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DummyBlobData(Context context, Random random, String fileName, String label) {
|
public Context getContext() {
|
||||||
this(context, DEFAULT_SIZE_BYTES, random, fileName, label);
|
return mContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DummyBlobData(Context context, long fileSize, Random random, String fileName,
|
public Builder setRandomSeed(int randomSeed) {
|
||||||
String label) {
|
mRandomSeed = randomSeed;
|
||||||
mContext = context;
|
return this;
|
||||||
mRandom = random;
|
}
|
||||||
mFile = new File(mContext.getFilesDir(), fileName);
|
|
||||||
mFileSize = fileSize;
|
public int getRandomSeed() {
|
||||||
mLabel = label;
|
return mRandomSeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setFileSize(int fileSize) {
|
||||||
|
mFileSize = fileSize;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getFileSize() {
|
||||||
|
return mFileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setLabel(CharSequence label) {
|
||||||
|
mLabel = label;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharSequence getLabel() {
|
||||||
|
return mLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setFileName(String fileName) {
|
||||||
|
mFileName = fileName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileName() {
|
||||||
|
return mFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DummyBlobData build() {
|
||||||
|
return new DummyBlobData(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void prepare() throws Exception {
|
public void prepare() throws Exception {
|
||||||
|
|||||||
@@ -16,7 +16,13 @@
|
|||||||
|
|
||||||
package com.android.utils.blob;
|
package com.android.utils.blob;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.app.blob.BlobHandle;
|
||||||
import android.app.blob.BlobStoreManager;
|
import android.app.blob.BlobStoreManager;
|
||||||
|
import android.app.blob.LeaseInfo;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@@ -56,4 +62,76 @@ public class Utils {
|
|||||||
copy(in, out, lengthBytes);
|
copy(in, out, lengthBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void assertLeasedBlobs(BlobStoreManager blobStoreManager,
|
||||||
|
BlobHandle... expectedBlobHandles) throws IOException {
|
||||||
|
assertThat(blobStoreManager.getLeasedBlobs()).containsExactly(expectedBlobHandles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertNoLeasedBlobs(BlobStoreManager blobStoreManager)
|
||||||
|
throws IOException {
|
||||||
|
assertThat(blobStoreManager.getLeasedBlobs()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void acquireLease(Context context,
|
||||||
|
BlobHandle blobHandle, CharSequence description) throws IOException {
|
||||||
|
final BlobStoreManager blobStoreManager = (BlobStoreManager) context.getSystemService(
|
||||||
|
Context.BLOB_STORE_SERVICE);
|
||||||
|
blobStoreManager.acquireLease(blobHandle, description);
|
||||||
|
|
||||||
|
final LeaseInfo leaseInfo = blobStoreManager.getLeaseInfo(blobHandle);
|
||||||
|
assertLeaseInfo(leaseInfo, context.getPackageName(), 0,
|
||||||
|
Resources.ID_NULL, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void acquireLease(Context context,
|
||||||
|
BlobHandle blobHandle, int descriptionResId) throws IOException {
|
||||||
|
final BlobStoreManager blobStoreManager = (BlobStoreManager) context.getSystemService(
|
||||||
|
Context.BLOB_STORE_SERVICE);
|
||||||
|
blobStoreManager.acquireLease(blobHandle, descriptionResId);
|
||||||
|
|
||||||
|
final LeaseInfo leaseInfo = blobStoreManager.getLeaseInfo(blobHandle);
|
||||||
|
assertLeaseInfo(leaseInfo, context.getPackageName(), 0,
|
||||||
|
descriptionResId, context.getString(descriptionResId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void acquireLease(Context context,
|
||||||
|
BlobHandle blobHandle, CharSequence description,
|
||||||
|
long expiryTimeMs) throws IOException {
|
||||||
|
final BlobStoreManager blobStoreManager = (BlobStoreManager) context.getSystemService(
|
||||||
|
Context.BLOB_STORE_SERVICE);
|
||||||
|
blobStoreManager.acquireLease(blobHandle, description, expiryTimeMs);
|
||||||
|
|
||||||
|
final LeaseInfo leaseInfo = blobStoreManager.getLeaseInfo(blobHandle);
|
||||||
|
assertLeaseInfo(leaseInfo, context.getPackageName(), expiryTimeMs,
|
||||||
|
Resources.ID_NULL, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void acquireLease(Context context,
|
||||||
|
BlobHandle blobHandle, int descriptionResId,
|
||||||
|
long expiryTimeMs) throws IOException {
|
||||||
|
final BlobStoreManager blobStoreManager = (BlobStoreManager) context.getSystemService(
|
||||||
|
Context.BLOB_STORE_SERVICE);
|
||||||
|
blobStoreManager.acquireLease(blobHandle, descriptionResId, expiryTimeMs);
|
||||||
|
|
||||||
|
final LeaseInfo leaseInfo = blobStoreManager.getLeaseInfo(blobHandle);
|
||||||
|
assertLeaseInfo(leaseInfo, context.getPackageName(), expiryTimeMs,
|
||||||
|
descriptionResId, context.getString(descriptionResId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void releaseLease(Context context,
|
||||||
|
BlobHandle blobHandle) throws IOException {
|
||||||
|
final BlobStoreManager blobStoreManager = (BlobStoreManager) context.getSystemService(
|
||||||
|
Context.BLOB_STORE_SERVICE);
|
||||||
|
blobStoreManager.releaseLease(blobHandle);
|
||||||
|
assertThat(blobStoreManager.getLeaseInfo(blobHandle)).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertLeaseInfo(LeaseInfo leaseInfo, String packageName,
|
||||||
|
long expiryTimeMs, int descriptionResId, CharSequence description) {
|
||||||
|
assertThat(leaseInfo.getPackageName()).isEqualTo(packageName);
|
||||||
|
assertThat(leaseInfo.getExpiryTimeMillis()).isEqualTo(expiryTimeMs);
|
||||||
|
assertThat(leaseInfo.getDescriptionResId()).isEqualTo(descriptionResId);
|
||||||
|
assertThat(leaseInfo.getDescription()).isEqualTo(description);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user