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

Commit aa5ba4f7 authored by Svet Ganov's avatar Svet Ganov Committed by Svetoslav Ganov
Browse files

[DO NOT MERGE] Handle config override via settings correctly

Initialize persistence only after we can read the settings
provider as we need to take into account the current config
potentially set as an override in settings vs using the
hard coded defaults.

Make the last persist time more robust to ensure it always
termines to guard against other unforeseen cases wehere the
persistet files don't match what is expected under the current
config.

Test: atest CtsAppOpsTestCases
Test: atest android.appsecurity.cts.AppOpsTest

bug:134093967

Change-Id: I211d267ccca044093d83dc5928f0531afa47791e
parent fd979ca3
Loading
Loading
Loading
Loading
+117 −30
Original line number Original line Diff line number Diff line
@@ -108,6 +108,12 @@ import java.util.concurrent.TimeUnit;
 * must be called with the mInMemoryLock, xxxDMLocked suffix means the method
 * must be called with the mInMemoryLock, xxxDMLocked suffix means the method
 * must be called with the mOnDiskLock and mInMemoryLock locks acquired in that
 * must be called with the mOnDiskLock and mInMemoryLock locks acquired in that
 * exact order.
 * exact order.
 * <p>
 * INITIALIZATION: We can initialize persistence only after the system is ready
 * as we need to check the optional configuration override from the settings
 * database which is not initialized at the time the app ops service is created.
 * This means that all entry points that touch persistence should be short
 * circuited via isPersistenceInitialized() check.
 */
 */
// TODO (bug:122218838): Make sure we handle start of epoch time
// TODO (bug:122218838): Make sure we handle start of epoch time
// TODO (bug:122218838): Validate changed time is handled correctly
// TODO (bug:122218838): Validate changed time is handled correctly
@@ -177,14 +183,33 @@ final class HistoricalRegistry {


    // Object managing persistence (read/write)
    // Object managing persistence (read/write)
    @GuardedBy("mOnDiskLock")
    @GuardedBy("mOnDiskLock")
    private Persistence mPersistence = new Persistence(mBaseSnapshotInterval,
    private Persistence mPersistence;
            mIntervalCompressionMultiplier);


    HistoricalRegistry(@NonNull Object lock) {
    HistoricalRegistry(@NonNull Object lock) {
        mInMemoryLock = lock;
        mInMemoryLock = lock;
        if (mMode != AppOpsManager.HISTORICAL_MODE_DISABLED) {
    }

    void systemReady(@NonNull ContentResolver resolver) {
        final Uri uri = Settings.Global.getUriFor(Settings.Global.APPOP_HISTORY_PARAMETERS);
        resolver.registerContentObserver(uri, false, new ContentObserver(
                FgThread.getHandler()) {
            @Override
            public void onChange(boolean selfChange) {
                updateParametersFromSetting(resolver);
            }
        });

        updateParametersFromSetting(resolver);

        synchronized (mOnDiskLock) {
        synchronized (mOnDiskLock) {
            synchronized (mInMemoryLock) {
            synchronized (mInMemoryLock) {
                if (mMode != AppOpsManager.HISTORICAL_MODE_DISABLED) {
                    // Can be uninitialized if there is no config in the settings table.
                    if (!isPersistenceInitializedMLocked()) {
                        mPersistence = new Persistence(mBaseSnapshotInterval,
                                mIntervalCompressionMultiplier);
                    }

                    // When starting always adjust history to now.
                    // When starting always adjust history to now.
                    final long lastPersistTimeMills =
                    final long lastPersistTimeMills =
                            mPersistence.getLastPersistTimeMillisDLocked();
                            mPersistence.getLastPersistTimeMillisDLocked();
@@ -197,16 +222,8 @@ final class HistoricalRegistry {
        }
        }
    }
    }


    void systemReady(@NonNull ContentResolver resolver) {
    private boolean isPersistenceInitializedMLocked() {
        updateParametersFromSetting(resolver);
        return mPersistence != null;
        final Uri uri = Settings.Global.getUriFor(Settings.Global.APPOP_HISTORY_PARAMETERS);
        resolver.registerContentObserver(uri, false, new ContentObserver(
                FgThread.getHandler()) {
            @Override
            public void onChange(boolean selfChange) {
                updateParametersFromSetting(resolver);
            }
        });
    }
    }


    private void updateParametersFromSetting(@NonNull ContentResolver resolver) {
    private void updateParametersFromSetting(@NonNull ContentResolver resolver) {
@@ -274,6 +291,11 @@ final class HistoricalRegistry {
                makeRelativeToEpochStart(currentOps, nowMillis);
                makeRelativeToEpochStart(currentOps, nowMillis);
                currentOps.accept(visitor);
                currentOps.accept(visitor);


                if(isPersistenceInitializedMLocked()) {
                    Slog.e(LOG_TAG, "Interaction before persistence initialized");
                    return;
                }

                final List<HistoricalOps> ops = mPersistence.readHistoryDLocked();
                final List<HistoricalOps> ops = mPersistence.readHistoryDLocked();
                if (ops != null) {
                if (ops != null) {
                    // TODO (bug:122218838): Make sure this is properly dumped
                    // TODO (bug:122218838): Make sure this is properly dumped
@@ -302,6 +324,13 @@ final class HistoricalRegistry {
    void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
    void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
            @OpFlags int flags, @NonNull RemoteCallback callback) {
            @OpFlags int flags, @NonNull RemoteCallback callback) {
        synchronized (mOnDiskLock) {
            synchronized (mInMemoryLock) {
                if (!isPersistenceInitializedMLocked()) {
                    Slog.e(LOG_TAG, "Interaction before persistence initialized");
                    callback.sendResult(new Bundle());
                    return;
                }
                final HistoricalOps result = new HistoricalOps(beginTimeMillis, endTimeMillis);
                final HistoricalOps result = new HistoricalOps(beginTimeMillis, endTimeMillis);
                mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, opNames,
                mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, opNames,
                        beginTimeMillis, endTimeMillis, flags);
                        beginTimeMillis, endTimeMillis, flags);
@@ -309,6 +338,8 @@ final class HistoricalRegistry {
                payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
                payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
                callback.sendResult(payload);
                callback.sendResult(payload);
            }
            }
        }
    }


    void getHistoricalOps(int uid, @NonNull String packageName,
    void getHistoricalOps(int uid, @NonNull String packageName,
            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
@@ -331,6 +362,12 @@ final class HistoricalRegistry {
            boolean collectOpsFromDisk;
            boolean collectOpsFromDisk;


            synchronized (mInMemoryLock) {
            synchronized (mInMemoryLock) {
                if (!isPersistenceInitializedMLocked()) {
                    Slog.e(LOG_TAG, "Interaction before persistence initialized");
                    callback.sendResult(new Bundle());
                    return;
                }

                currentOps = getUpdatedPendingHistoricalOpsMLocked(currentTimeMillis);
                currentOps = getUpdatedPendingHistoricalOpsMLocked(currentTimeMillis);
                if (!(inMemoryAdjBeginTimeMillis >= currentOps.getEndTimeMillis()
                if (!(inMemoryAdjBeginTimeMillis >= currentOps.getEndTimeMillis()
                        || inMemoryAdjEndTimeMillis <= currentOps.getBeginTimeMillis())) {
                        || inMemoryAdjEndTimeMillis <= currentOps.getBeginTimeMillis())) {
@@ -374,6 +411,10 @@ final class HistoricalRegistry {
            @UidState int uidState, @OpFlags int flags) {
            @UidState int uidState, @OpFlags int flags) {
        synchronized (mInMemoryLock) {
        synchronized (mInMemoryLock) {
            if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
            if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
                if (!isPersistenceInitializedMLocked()) {
                    Slog.e(LOG_TAG, "Interaction before persistence initialized");
                    return;
                }
                getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
                getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
                        .increaseAccessCount(op, uid, packageName, uidState, flags, 1);
                        .increaseAccessCount(op, uid, packageName, uidState, flags, 1);
            }
            }
@@ -384,6 +425,10 @@ final class HistoricalRegistry {
            @UidState int uidState, @OpFlags int flags) {
            @UidState int uidState, @OpFlags int flags) {
        synchronized (mInMemoryLock) {
        synchronized (mInMemoryLock) {
            if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
            if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
                if (!isPersistenceInitializedMLocked()) {
                    Slog.e(LOG_TAG, "Interaction before persistence initialized");
                    return;
                }
                getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
                getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
                        .increaseRejectCount(op, uid, packageName, uidState, flags, 1);
                        .increaseRejectCount(op, uid, packageName, uidState, flags, 1);
            }
            }
@@ -394,6 +439,10 @@ final class HistoricalRegistry {
            @UidState int uidState, @OpFlags int flags, long increment) {
            @UidState int uidState, @OpFlags int flags, long increment) {
        synchronized (mInMemoryLock) {
        synchronized (mInMemoryLock) {
            if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
            if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
                if (!isPersistenceInitializedMLocked()) {
                    Slog.e(LOG_TAG, "Interaction before persistence initialized");
                    return;
                }
                getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
                getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
                        .increaseAccessDuration(op, uid, packageName, uidState, flags, increment);
                        .increaseAccessDuration(op, uid, packageName, uidState, flags, increment);
            }
            }
@@ -404,6 +453,8 @@ final class HistoricalRegistry {
            long baseSnapshotInterval, long intervalCompressionMultiplier) {
            long baseSnapshotInterval, long intervalCompressionMultiplier) {
        synchronized (mOnDiskLock) {
        synchronized (mOnDiskLock) {
            synchronized (mInMemoryLock) {
            synchronized (mInMemoryLock) {
                // NOTE: We allow this call if persistence is not initialized as
                // it is a part of the persistence initialization process.
                boolean resampleHistory = false;
                boolean resampleHistory = false;
                Slog.i(LOG_TAG, "New history parameters: mode:"
                Slog.i(LOG_TAG, "New history parameters: mode:"
                        + AppOpsManager.historicalModeToString(mMode) + " baseSnapshotInterval:"
                        + AppOpsManager.historicalModeToString(mMode) + " baseSnapshotInterval:"
@@ -412,7 +463,7 @@ final class HistoricalRegistry {
                if (mMode != mode) {
                if (mMode != mode) {
                    mMode = mode;
                    mMode = mode;
                    if (mMode == AppOpsManager.HISTORICAL_MODE_DISABLED) {
                    if (mMode == AppOpsManager.HISTORICAL_MODE_DISABLED) {
                        clearHistoryOnDiskLocked();
                        clearHistoryOnDiskDLocked();
                    }
                    }
                }
                }
                if (mBaseSnapshotInterval != baseSnapshotInterval) {
                if (mBaseSnapshotInterval != baseSnapshotInterval) {
@@ -433,6 +484,10 @@ final class HistoricalRegistry {
    void offsetHistory(long offsetMillis) {
    void offsetHistory(long offsetMillis) {
        synchronized (mOnDiskLock) {
        synchronized (mOnDiskLock) {
            synchronized (mInMemoryLock) {
            synchronized (mInMemoryLock) {
                if (!isPersistenceInitializedMLocked()) {
                    Slog.e(LOG_TAG, "Interaction before persistence initialized");
                    return;
                }
                final List<HistoricalOps> history = mPersistence.readHistoryDLocked();
                final List<HistoricalOps> history = mPersistence.readHistoryDLocked();
                clearHistory();
                clearHistory();
                if (history != null) {
                if (history != null) {
@@ -453,6 +508,10 @@ final class HistoricalRegistry {
    void addHistoricalOps(HistoricalOps ops) {
    void addHistoricalOps(HistoricalOps ops) {
        final List<HistoricalOps> pendingWrites;
        final List<HistoricalOps> pendingWrites;
        synchronized (mInMemoryLock) {
        synchronized (mInMemoryLock) {
            if (!isPersistenceInitializedMLocked()) {
                Slog.e(LOG_TAG, "Interaction before persistence initialized");
                return;
            }
            // The history files start from mBaseSnapshotInterval - take this into account.
            // The history files start from mBaseSnapshotInterval - take this into account.
            ops.offsetBeginAndEndTime(mBaseSnapshotInterval);
            ops.offsetBeginAndEndTime(mBaseSnapshotInterval);
            mPendingWrites.offerFirst(ops);
            mPendingWrites.offerFirst(ops);
@@ -468,6 +527,10 @@ final class HistoricalRegistry {
    }
    }


    void resetHistoryParameters() {
    void resetHistoryParameters() {
        if (!isPersistenceInitializedMLocked()) {
            Slog.e(LOG_TAG, "Interaction before persistence initialized");
            return;
        }
        setHistoryParameters(DEFAULT_MODE, DEFAULT_SNAPSHOT_INTERVAL_MILLIS,
        setHistoryParameters(DEFAULT_MODE, DEFAULT_SNAPSHOT_INTERVAL_MILLIS,
                DEFAULT_COMPRESSION_STEP);
                DEFAULT_COMPRESSION_STEP);
    }
    }
@@ -475,6 +538,10 @@ final class HistoricalRegistry {
    void clearHistory(int uid, String packageName) {
    void clearHistory(int uid, String packageName) {
        synchronized (mOnDiskLock) {
        synchronized (mOnDiskLock) {
            synchronized (mInMemoryLock) {
            synchronized (mInMemoryLock) {
                if (!isPersistenceInitializedMLocked()) {
                    Slog.e(LOG_TAG, "Interaction before persistence initialized");
                    return;
                }
                if (mMode != AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
                if (mMode != AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
                    return;
                    return;
                }
                }
@@ -493,11 +560,17 @@ final class HistoricalRegistry {


    void clearHistory() {
    void clearHistory() {
        synchronized (mOnDiskLock) {
        synchronized (mOnDiskLock) {
            clearHistoryOnDiskLocked();
            synchronized (mInMemoryLock) {
                if (!isPersistenceInitializedMLocked()) {
                    Slog.e(LOG_TAG, "Interaction before persistence initialized");
                    return;
                }
                clearHistoryOnDiskDLocked();
            }
        }
        }
    }
    }


    private void clearHistoryOnDiskLocked() {
    private void clearHistoryOnDiskDLocked() {
        BackgroundThread.getHandler().removeMessages(MSG_WRITE_PENDING_HISTORY);
        BackgroundThread.getHandler().removeMessages(MSG_WRITE_PENDING_HISTORY);
        synchronized (mInMemoryLock) {
        synchronized (mInMemoryLock) {
            mCurrentHistoricalOps = null;
            mCurrentHistoricalOps = null;
@@ -718,13 +791,27 @@ final class HistoricalRegistry {
                baseDir = mHistoricalAppOpsDir.startRead();
                baseDir = mHistoricalAppOpsDir.startRead();
                final File[] files = baseDir.listFiles();
                final File[] files = baseDir.listFiles();
                if (files != null && files.length > 0) {
                if (files != null && files.length > 0) {
                    final Set<File> historyFiles = new ArraySet<>();
                    File shortestFile = null;
                    Collections.addAll(historyFiles, files);
                    for (File candidate : files) {
                    for (int i = 0;; i++) {
                        final String candidateName = candidate.getName();
                        final File file = generateFile(baseDir, i);
                        if (!candidateName.endsWith(HISTORY_FILE_SUFFIX)) {
                        if (historyFiles.contains(file)) {
                            continue;
                            return file.lastModified();
                        }
                        if (shortestFile == null) {
                            shortestFile = candidate;
                        } else if (candidateName.length() < shortestFile.getName().length()) {
                            shortestFile = candidate;
                        }
                    }
                    }
                    if (shortestFile == null) {
                        return 0;
                    }
                    final String shortestNameNoExtension = shortestFile.getName()
                            .replace(HISTORY_FILE_SUFFIX, "");
                    try {
                        return Long.parseLong(shortestNameNoExtension);
                    } catch (NumberFormatException e) {
                        return 0;
                    }
                    }
                }
                }
                mHistoricalAppOpsDir.finishRead();
                mHistoricalAppOpsDir.finishRead();