Merge "Keep track of commit times for each blob." into rvc-dev am: b78a0f462e
Change-Id: I240071a9fbdce84d63d0ff80b4bcbe1e3323b2b6
This commit is contained in:
@@ -48,6 +48,7 @@ public final class XmlTags {
|
|||||||
|
|
||||||
// For committer
|
// For committer
|
||||||
public static final String TAG_COMMITTER = "c";
|
public static final String TAG_COMMITTER = "c";
|
||||||
|
public static final String ATTR_COMMIT_TIME_MS = "cmt";
|
||||||
|
|
||||||
// For leasee
|
// For leasee
|
||||||
public static final String TAG_LEASEE = "l";
|
public static final String TAG_LEASEE = "l";
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.server.blob;
|
package com.android.server.blob;
|
||||||
|
|
||||||
|
import static android.app.blob.XmlTags.ATTR_COMMIT_TIME_MS;
|
||||||
import static android.app.blob.XmlTags.ATTR_DESCRIPTION;
|
import static android.app.blob.XmlTags.ATTR_DESCRIPTION;
|
||||||
import static android.app.blob.XmlTags.ATTR_DESCRIPTION_RES_NAME;
|
import static android.app.blob.XmlTags.ATTR_DESCRIPTION_RES_NAME;
|
||||||
import static android.app.blob.XmlTags.ATTR_EXPIRY_TIME;
|
import static android.app.blob.XmlTags.ATTR_EXPIRY_TIME;
|
||||||
@@ -30,6 +31,7 @@ import static android.os.Process.INVALID_UID;
|
|||||||
import static android.system.OsConstants.O_RDONLY;
|
import static android.system.OsConstants.O_RDONLY;
|
||||||
|
|
||||||
import static com.android.server.blob.BlobStoreConfig.TAG;
|
import static com.android.server.blob.BlobStoreConfig.TAG;
|
||||||
|
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_COMMIT_TIME;
|
||||||
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_DESC_RES_NAME;
|
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_DESC_RES_NAME;
|
||||||
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_STRING_DESC;
|
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_STRING_DESC;
|
||||||
import static com.android.server.blob.BlobStoreConfig.hasLeaseWaitTimeElapsed;
|
import static com.android.server.blob.BlobStoreConfig.hasLeaseWaitTimeElapsed;
|
||||||
@@ -54,6 +56,7 @@ import android.util.Slog;
|
|||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.util.IndentingPrintWriter;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
import com.android.internal.util.XmlUtils;
|
import com.android.internal.util.XmlUtils;
|
||||||
import com.android.server.blob.BlobStoreManagerService.DumpArgs;
|
import com.android.server.blob.BlobStoreManagerService.DumpArgs;
|
||||||
@@ -125,7 +128,7 @@ class BlobMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addCommitters(ArraySet<Committer> committers) {
|
void setCommitters(ArraySet<Committer> committers) {
|
||||||
synchronized (mMetadataLock) {
|
synchronized (mMetadataLock) {
|
||||||
mCommitters.clear();
|
mCommitters.clear();
|
||||||
mCommitters.addAll(committers);
|
mCommitters.addAll(committers);
|
||||||
@@ -153,12 +156,17 @@ class BlobMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
Committer getExistingCommitter(@NonNull Committer newCommitter) {
|
Committer getExistingCommitter(@NonNull String packageName, int uid) {
|
||||||
synchronized (mCommitters) {
|
synchronized (mCommitters) {
|
||||||
final int index = mCommitters.indexOf(newCommitter);
|
for (int i = 0, size = mCommitters.size(); i < size; ++i) {
|
||||||
return index >= 0 ? mCommitters.valueAt(index) : null;
|
final Committer committer = mCommitters.valueAt(i);
|
||||||
|
if (committer.uid == uid && committer.packageName.equals(packageName)) {
|
||||||
|
return committer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
void addOrReplaceLeasee(String callingPackage, int callingUid, int descriptionResId,
|
void addOrReplaceLeasee(String callingPackage, int callingUid, int descriptionResId,
|
||||||
CharSequence description, long leaseExpiryTimeMillis) {
|
CharSequence description, long leaseExpiryTimeMillis) {
|
||||||
@@ -172,7 +180,7 @@ class BlobMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addLeasees(ArraySet<Leasee> leasees) {
|
void setLeasees(ArraySet<Leasee> leasees) {
|
||||||
synchronized (mMetadataLock) {
|
synchronized (mMetadataLock) {
|
||||||
mLeasees.clear();
|
mLeasees.clear();
|
||||||
mLeasees.addAll(leasees);
|
mLeasees.addAll(leasees);
|
||||||
@@ -380,8 +388,7 @@ class BlobMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Blobs with no active leases
|
// Blobs with no active leases
|
||||||
// TODO: Track commit time instead of using last modified time.
|
if ((!respectLeaseWaitTime || hasLeaseWaitTimeElapsedForAll())
|
||||||
if ((!respectLeaseWaitTime || hasLeaseWaitTimeElapsed(getBlobFile().lastModified()))
|
|
||||||
&& !hasLeases()) {
|
&& !hasLeases()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -389,6 +396,17 @@ class BlobMetadata {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
boolean hasLeaseWaitTimeElapsedForAll() {
|
||||||
|
for (int i = 0, size = mCommitters.size(); i < size; ++i) {
|
||||||
|
final Committer committer = mCommitters.valueAt(i);
|
||||||
|
if (!hasLeaseWaitTimeElapsed(committer.getCommitTimeMs())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void dump(IndentingPrintWriter fout, DumpArgs dumpArgs) {
|
void dump(IndentingPrintWriter fout, DumpArgs dumpArgs) {
|
||||||
fout.println("blobHandle:");
|
fout.println("blobHandle:");
|
||||||
fout.increaseIndent();
|
fout.increaseIndent();
|
||||||
@@ -492,20 +510,28 @@ class BlobMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final BlobMetadata blobMetadata = new BlobMetadata(context, blobId, blobHandle, userId);
|
final BlobMetadata blobMetadata = new BlobMetadata(context, blobId, blobHandle, userId);
|
||||||
blobMetadata.addCommitters(committers);
|
blobMetadata.setCommitters(committers);
|
||||||
blobMetadata.addLeasees(leasees);
|
blobMetadata.setLeasees(leasees);
|
||||||
return blobMetadata;
|
return blobMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class Committer extends Accessor {
|
static final class Committer extends Accessor {
|
||||||
public final BlobAccessMode blobAccessMode;
|
public final BlobAccessMode blobAccessMode;
|
||||||
|
public final long commitTimeMs;
|
||||||
|
|
||||||
Committer(String packageName, int uid, BlobAccessMode blobAccessMode) {
|
Committer(String packageName, int uid, BlobAccessMode blobAccessMode, long commitTimeMs) {
|
||||||
super(packageName, uid);
|
super(packageName, uid);
|
||||||
this.blobAccessMode = blobAccessMode;
|
this.blobAccessMode = blobAccessMode;
|
||||||
|
this.commitTimeMs = commitTimeMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
long getCommitTimeMs() {
|
||||||
|
return commitTimeMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump(IndentingPrintWriter fout) {
|
void dump(IndentingPrintWriter fout) {
|
||||||
|
fout.println("commit time: "
|
||||||
|
+ (commitTimeMs == 0 ? "<null>" : BlobStoreUtils.formatTime(commitTimeMs)));
|
||||||
fout.println("accessMode:");
|
fout.println("accessMode:");
|
||||||
fout.increaseIndent();
|
fout.increaseIndent();
|
||||||
blobAccessMode.dump(fout);
|
blobAccessMode.dump(fout);
|
||||||
@@ -515,6 +541,7 @@ class BlobMetadata {
|
|||||||
void writeToXml(@NonNull XmlSerializer out) throws IOException {
|
void writeToXml(@NonNull XmlSerializer out) throws IOException {
|
||||||
XmlUtils.writeStringAttribute(out, ATTR_PACKAGE, packageName);
|
XmlUtils.writeStringAttribute(out, ATTR_PACKAGE, packageName);
|
||||||
XmlUtils.writeIntAttribute(out, ATTR_UID, uid);
|
XmlUtils.writeIntAttribute(out, ATTR_UID, uid);
|
||||||
|
XmlUtils.writeLongAttribute(out, ATTR_COMMIT_TIME_MS, commitTimeMs);
|
||||||
|
|
||||||
out.startTag(null, TAG_ACCESS_MODE);
|
out.startTag(null, TAG_ACCESS_MODE);
|
||||||
blobAccessMode.writeToXml(out);
|
blobAccessMode.writeToXml(out);
|
||||||
@@ -526,6 +553,9 @@ class BlobMetadata {
|
|||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
final String packageName = XmlUtils.readStringAttribute(in, ATTR_PACKAGE);
|
final String packageName = XmlUtils.readStringAttribute(in, ATTR_PACKAGE);
|
||||||
final int uid = XmlUtils.readIntAttribute(in, ATTR_UID);
|
final int uid = XmlUtils.readIntAttribute(in, ATTR_UID);
|
||||||
|
final long commitTimeMs = version >= XML_VERSION_ADD_COMMIT_TIME
|
||||||
|
? XmlUtils.readLongAttribute(in, ATTR_COMMIT_TIME_MS)
|
||||||
|
: 0;
|
||||||
|
|
||||||
final int depth = in.getDepth();
|
final int depth = in.getDepth();
|
||||||
BlobAccessMode blobAccessMode = null;
|
BlobAccessMode blobAccessMode = null;
|
||||||
@@ -538,7 +568,7 @@ class BlobMetadata {
|
|||||||
Slog.wtf(TAG, "blobAccessMode should be available");
|
Slog.wtf(TAG, "blobAccessMode should be available");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new Committer(packageName, uid, blobAccessMode);
|
return new Committer(packageName, uid, blobAccessMode, commitTimeMs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,8 +45,9 @@ class BlobStoreConfig {
|
|||||||
// Added a string variant of lease description.
|
// Added a string variant of lease description.
|
||||||
public static final int XML_VERSION_ADD_STRING_DESC = 2;
|
public static final int XML_VERSION_ADD_STRING_DESC = 2;
|
||||||
public static final int XML_VERSION_ADD_DESC_RES_NAME = 3;
|
public static final int XML_VERSION_ADD_DESC_RES_NAME = 3;
|
||||||
|
public static final int XML_VERSION_ADD_COMMIT_TIME = 4;
|
||||||
|
|
||||||
public static final int XML_VERSION_CURRENT = XML_VERSION_ADD_DESC_RES_NAME;
|
public static final int XML_VERSION_CURRENT = XML_VERSION_ADD_COMMIT_TIME;
|
||||||
|
|
||||||
private static final String ROOT_DIR_NAME = "blobstore";
|
private static final String ROOT_DIR_NAME = "blobstore";
|
||||||
private static final String BLOBS_DIR_NAME = "blobs";
|
private static final String BLOBS_DIR_NAME = "blobs";
|
||||||
@@ -100,6 +101,18 @@ class BlobStoreConfig {
|
|||||||
public static long LEASE_ACQUISITION_WAIT_DURATION_MS =
|
public static long LEASE_ACQUISITION_WAIT_DURATION_MS =
|
||||||
DEFAULT_LEASE_ACQUISITION_WAIT_DURATION_MS;
|
DEFAULT_LEASE_ACQUISITION_WAIT_DURATION_MS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denotes the duration from the time a blob is committed that any new commits of the same
|
||||||
|
* data blob from the same committer will be treated as if they occurred at the earlier
|
||||||
|
* commit time.
|
||||||
|
*/
|
||||||
|
public static final String KEY_COMMIT_COOL_OFF_DURATION_MS =
|
||||||
|
"commit_cool_off_duration_ms";
|
||||||
|
public static final long DEFAULT_COMMIT_COOL_OFF_DURATION_MS =
|
||||||
|
TimeUnit.HOURS.toMillis(48);
|
||||||
|
public static long COMMIT_COOL_OFF_DURATION_MS =
|
||||||
|
DEFAULT_COMMIT_COOL_OFF_DURATION_MS;
|
||||||
|
|
||||||
static void refresh(Properties properties) {
|
static void refresh(Properties properties) {
|
||||||
if (!NAMESPACE_BLOBSTORE.equals(properties.getNamespace())) {
|
if (!NAMESPACE_BLOBSTORE.equals(properties.getNamespace())) {
|
||||||
return;
|
return;
|
||||||
@@ -163,6 +176,27 @@ class BlobStoreConfig {
|
|||||||
< System.currentTimeMillis();
|
< System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an adjusted commit time depending on whether commit cool-off period has elapsed.
|
||||||
|
*
|
||||||
|
* If this is the initial commit or the earlier commit cool-off period has elapsed, then
|
||||||
|
* the new commit time is used. Otherwise, the earlier commit time is used.
|
||||||
|
*/
|
||||||
|
public static long getAdjustedCommitTimeMs(long oldCommitTimeMs, long newCommitTimeMs) {
|
||||||
|
if (oldCommitTimeMs == 0 || hasCommitCoolOffPeriodElapsed(oldCommitTimeMs)) {
|
||||||
|
return newCommitTimeMs;
|
||||||
|
}
|
||||||
|
return oldCommitTimeMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the commit cool-off period has elapsed.
|
||||||
|
*/
|
||||||
|
private static boolean hasCommitCoolOffPeriodElapsed(long commitTimeMs) {
|
||||||
|
return commitTimeMs + DeviceConfigProperties.COMMIT_COOL_OFF_DURATION_MS
|
||||||
|
< System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static File prepareBlobFile(long sessionId) {
|
public static File prepareBlobFile(long sessionId) {
|
||||||
final File blobsDir = prepareBlobsDir();
|
final File blobsDir = prepareBlobsDir();
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import static com.android.server.blob.BlobStoreConfig.LOGV;
|
|||||||
import static com.android.server.blob.BlobStoreConfig.SESSION_EXPIRY_TIMEOUT_MILLIS;
|
import static com.android.server.blob.BlobStoreConfig.SESSION_EXPIRY_TIMEOUT_MILLIS;
|
||||||
import static com.android.server.blob.BlobStoreConfig.TAG;
|
import static com.android.server.blob.BlobStoreConfig.TAG;
|
||||||
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_CURRENT;
|
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_CURRENT;
|
||||||
|
import static com.android.server.blob.BlobStoreConfig.getAdjustedCommitTimeMs;
|
||||||
import static com.android.server.blob.BlobStoreSession.STATE_ABANDONED;
|
import static com.android.server.blob.BlobStoreSession.STATE_ABANDONED;
|
||||||
import static com.android.server.blob.BlobStoreSession.STATE_COMMITTED;
|
import static com.android.server.blob.BlobStoreSession.STATE_COMMITTED;
|
||||||
import static com.android.server.blob.BlobStoreSession.STATE_VERIFIED_INVALID;
|
import static com.android.server.blob.BlobStoreSession.STATE_VERIFIED_INVALID;
|
||||||
@@ -566,13 +567,18 @@ public class BlobStoreManagerService extends SystemService {
|
|||||||
userId);
|
userId);
|
||||||
BlobMetadata blob = userBlobs.get(session.getBlobHandle());
|
BlobMetadata blob = userBlobs.get(session.getBlobHandle());
|
||||||
if (blob == null) {
|
if (blob == null) {
|
||||||
blob = new BlobMetadata(mContext,
|
blob = new BlobMetadata(mContext, session.getSessionId(),
|
||||||
session.getSessionId(), session.getBlobHandle(), userId);
|
session.getBlobHandle(), userId);
|
||||||
addBlobForUserLocked(blob, userBlobs);
|
addBlobForUserLocked(blob, userBlobs);
|
||||||
}
|
}
|
||||||
|
final Committer existingCommitter = blob.getExistingCommitter(
|
||||||
|
session.getOwnerPackageName(), session.getOwnerUid());
|
||||||
|
final long existingCommitTimeMs =
|
||||||
|
(existingCommitter == null) ? 0 : existingCommitter.getCommitTimeMs();
|
||||||
final Committer newCommitter = new Committer(session.getOwnerPackageName(),
|
final Committer newCommitter = new Committer(session.getOwnerPackageName(),
|
||||||
session.getOwnerUid(), session.getBlobAccessMode());
|
session.getOwnerUid(), session.getBlobAccessMode(),
|
||||||
final Committer existingCommitter = blob.getExistingCommitter(newCommitter);
|
getAdjustedCommitTimeMs(existingCommitTimeMs,
|
||||||
|
System.currentTimeMillis()));
|
||||||
blob.addOrReplaceCommitter(newCommitter);
|
blob.addOrReplaceCommitter(newCommitter);
|
||||||
try {
|
try {
|
||||||
writeBlobsInfoLocked();
|
writeBlobsInfoLocked();
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import android.annotation.Nullable;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.text.format.TimeMigrationUtils;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
class BlobStoreUtils {
|
class BlobStoreUtils {
|
||||||
@@ -56,4 +57,9 @@ class BlobStoreUtils {
|
|||||||
? Resources.ID_NULL
|
? Resources.ID_NULL
|
||||||
: getDescriptionResourceId(resources, resourceEntryName, packageName);
|
: getDescriptionResourceId(resources, resourceEntryName, packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
static String formatTime(long timeMs) {
|
||||||
|
return TimeMigrationUtils.formatMillisWithFixedFormat(timeMs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -382,6 +382,7 @@ public class BlobStoreManagerServiceTest {
|
|||||||
doReturn(hasLeases).when(blobMetadata).hasLeases();
|
doReturn(hasLeases).when(blobMetadata).hasLeases();
|
||||||
doReturn(blobHandle).when(blobMetadata).getBlobHandle();
|
doReturn(blobHandle).when(blobMetadata).getBlobHandle();
|
||||||
doCallRealMethod().when(blobMetadata).shouldBeDeleted(anyBoolean());
|
doCallRealMethod().when(blobMetadata).shouldBeDeleted(anyBoolean());
|
||||||
|
doReturn(true).when(blobMetadata).hasLeaseWaitTimeElapsedForAll();
|
||||||
return blobMetadata;
|
return blobMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user