Merge "Fix a race in persisting instant cookie"
This commit is contained in:
committed by
Android (Google) Code Review
commit
5653fd68f9
@@ -117,7 +117,13 @@ class InstantAppRegistry {
|
||||
|
||||
public byte[] getInstantAppCookieLPw(@NonNull String packageName,
|
||||
@UserIdInt int userId) {
|
||||
byte[] pendingCookie = mCookiePersistence.getPendingPersistCookie(userId, packageName);
|
||||
// Only installed packages can get their own cookie
|
||||
PackageParser.Package pkg = mService.mPackages.get(packageName);
|
||||
if (pkg == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] pendingCookie = mCookiePersistence.getPendingPersistCookieLPr(pkg, userId);
|
||||
if (pendingCookie != null) {
|
||||
return pendingCookie;
|
||||
}
|
||||
@@ -144,14 +150,13 @@ class InstantAppRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
// Only an installed package can set its own cookie
|
||||
PackageParser.Package pkg = mService.mPackages.get(packageName);
|
||||
if (pkg == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File cookieFile = computeInstantCookieFile(pkg, userId);
|
||||
|
||||
mCookiePersistence.schedulePersist(userId, packageName, cookieFile, cookie);
|
||||
mCookiePersistence.schedulePersistLPw(userId, pkg, cookie);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -172,12 +177,11 @@ class InstantAppRegistry {
|
||||
if (cookie == null || cookie.length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(cookieFile)) {
|
||||
fos.write(cookie, 0, cookie.length);
|
||||
} catch (IOException e) {
|
||||
Slog.e(LOG_TAG, "Error writing instant app cookie file: " + cookieFile, e);
|
||||
}
|
||||
}
|
||||
try (FileOutputStream fos = new FileOutputStream(cookieFile)) {
|
||||
fos.write(cookie, 0, cookie.length);
|
||||
} catch (IOException e) {
|
||||
Slog.e(LOG_TAG, "Error writing instant app cookie file: " + cookieFile, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,6 +246,8 @@ class InstantAppRegistry {
|
||||
if (!currentCookieFile.equals(expectedCookeFile)) {
|
||||
Slog.i(LOG_TAG, "Signature for package " + pkg.packageName
|
||||
+ " changed - dropping cookie");
|
||||
// Make sure a pending write for the old signed app is cancelled
|
||||
mCookiePersistence.cancelPendingPersistLPw(pkg, userId);
|
||||
currentCookieFile.delete();
|
||||
}
|
||||
}
|
||||
@@ -894,75 +900,88 @@ class InstantAppRegistry {
|
||||
// Handler allows removing messages by id and tag where the
|
||||
// tag is compared using ==. So to allow cancelling the
|
||||
// pending persistence for an app under a given user we use
|
||||
// the fact that package names are interned in the system
|
||||
// process so the == comparison would match and we end up
|
||||
// with a way to cancel persisting the cookie for a user
|
||||
// and package.
|
||||
private final SparseArray<ArrayMap<String, byte[]>> mPendingPersistCookies =
|
||||
new SparseArray<>();
|
||||
// the fact that package are cached by the system so the ==
|
||||
// comparison would match and we end up with a way to cancel
|
||||
// persisting the cookie for a user and package.
|
||||
private final SparseArray<ArrayMap<PackageParser.Package, SomeArgs>> mPendingPersistCookies
|
||||
= new SparseArray<>();
|
||||
|
||||
public CookiePersistence(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
public void schedulePersist(@UserIdInt int userId, @NonNull String packageName,
|
||||
@NonNull File cookieFile, @NonNull byte[] cookie) {
|
||||
cancelPendingPersist(userId, packageName);
|
||||
addPendingPersistCookie(userId, packageName, cookie);
|
||||
SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = packageName;
|
||||
args.arg2 = cookieFile;
|
||||
sendMessageDelayed(obtainMessage(userId, args),
|
||||
public void schedulePersistLPw(@UserIdInt int userId, @NonNull PackageParser.Package pkg,
|
||||
@NonNull byte[] cookie) {
|
||||
File cookieFile = computeInstantCookieFile(pkg, userId);
|
||||
cancelPendingPersistLPw(pkg, userId);
|
||||
addPendingPersistCookieLPw(userId, pkg, cookie, cookieFile);
|
||||
sendMessageDelayed(obtainMessage(userId, pkg),
|
||||
PERSIST_COOKIE_DELAY_MILLIS);
|
||||
}
|
||||
|
||||
public @Nullable byte[] getPendingPersistCookie(@UserIdInt int userId,
|
||||
@NonNull String packageName) {
|
||||
ArrayMap<String, byte[]> pendingWorkForUser = mPendingPersistCookies.get(userId);
|
||||
public @Nullable byte[] getPendingPersistCookieLPr(@NonNull PackageParser.Package pkg,
|
||||
@UserIdInt int userId) {
|
||||
ArrayMap<PackageParser.Package, SomeArgs> pendingWorkForUser =
|
||||
mPendingPersistCookies.get(userId);
|
||||
if (pendingWorkForUser != null) {
|
||||
return pendingWorkForUser.remove(packageName);
|
||||
SomeArgs state = pendingWorkForUser.get(pkg);
|
||||
if (state != null) {
|
||||
return (byte[]) state.arg1;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void cancelPendingPersist(@UserIdInt int userId,
|
||||
@NonNull String packageName) {
|
||||
removePendingPersistCookie(userId, packageName);
|
||||
removeMessages(userId, packageName);
|
||||
public void cancelPendingPersistLPw(@NonNull PackageParser.Package pkg,
|
||||
@UserIdInt int userId) {
|
||||
removeMessages(userId, pkg);
|
||||
SomeArgs state = removePendingPersistCookieLPr(pkg, userId);
|
||||
if (state != null) {
|
||||
state.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
private void addPendingPersistCookie(@UserIdInt int userId,
|
||||
@NonNull String packageName, @NonNull byte[] cookie) {
|
||||
ArrayMap<String, byte[]> pendingWorkForUser = mPendingPersistCookies.get(userId);
|
||||
private void addPendingPersistCookieLPw(@UserIdInt int userId,
|
||||
@NonNull PackageParser.Package pkg, @NonNull byte[] cookie,
|
||||
@NonNull File cookieFile) {
|
||||
ArrayMap<PackageParser.Package, SomeArgs> pendingWorkForUser =
|
||||
mPendingPersistCookies.get(userId);
|
||||
if (pendingWorkForUser == null) {
|
||||
pendingWorkForUser = new ArrayMap<>();
|
||||
mPendingPersistCookies.put(userId, pendingWorkForUser);
|
||||
}
|
||||
pendingWorkForUser.put(packageName, cookie);
|
||||
SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = cookie;
|
||||
args.arg2 = cookieFile;
|
||||
pendingWorkForUser.put(pkg, args);
|
||||
}
|
||||
|
||||
private byte[] removePendingPersistCookie(@UserIdInt int userId,
|
||||
@NonNull String packageName) {
|
||||
ArrayMap<String, byte[]> pendingWorkForUser = mPendingPersistCookies.get(userId);
|
||||
byte[] cookie = null;
|
||||
private SomeArgs removePendingPersistCookieLPr(@NonNull PackageParser.Package pkg,
|
||||
@UserIdInt int userId) {
|
||||
ArrayMap<PackageParser.Package, SomeArgs> pendingWorkForUser =
|
||||
mPendingPersistCookies.get(userId);
|
||||
SomeArgs state = null;
|
||||
if (pendingWorkForUser != null) {
|
||||
cookie = pendingWorkForUser.remove(packageName);
|
||||
state = pendingWorkForUser.remove(pkg);
|
||||
if (pendingWorkForUser.isEmpty()) {
|
||||
mPendingPersistCookies.remove(userId);
|
||||
}
|
||||
}
|
||||
return cookie;
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
int userId = message.what;
|
||||
SomeArgs args = (SomeArgs) message.obj;
|
||||
String packageName = (String) args.arg1;
|
||||
File cookieFile = (File) args.arg2;
|
||||
args.recycle();
|
||||
byte[] cookie = removePendingPersistCookie(userId, packageName);
|
||||
persistInstantApplicationCookie(cookie, packageName, cookieFile, userId);
|
||||
PackageParser.Package pkg = (PackageParser.Package) message.obj;
|
||||
SomeArgs state = removePendingPersistCookieLPr(pkg, userId);
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
byte[] cookie = (byte[]) state.arg1;
|
||||
File cookieFile = (File) state.arg2;
|
||||
state.recycle();
|
||||
persistInstantApplicationCookie(cookie, pkg.packageName, cookieFile, userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user