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