Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5653fd68 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix a race in persisting instant cookie"

parents 04215148 312c6cc6
Loading
Loading
Loading
Loading
+67 −48
Original line number Original line Diff line number Diff line
@@ -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;
        }
        }
@@ -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;
    }
    }


@@ -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) {
@@ -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();
            }
            }
        }
        }
@@ -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);
        }
        }
    }
    }
}
}