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

Commit 8455ba23 authored by Svet Ganov's avatar Svet Ganov
Browse files

Historical app ops.

This change is the main check in for the historical app op feature.
The idea is to store a historical data about past app op rejections,
accesses, and durations per op for any UID state indefinitely.

Keeping all operations on record is not practical as app ops are
very frequently performed. To address this we are storing aggregated
data as snapshots where we store for every UID and its packages
how many times each op was accessed, rejected, lasted as an aggregate.

To allow history scaling indefinitely we are taking a logarithmic
approach with only the most recent state stored in memory and all
preceding state stored on disk. State on disk is stored in separate
files where each preceding file, i.e. for an older period, would
cover X times longer period with X number of snapshots covering
X times longer period. Initially X is ten but can be tweaked. For
example, the first file could contain data for ten days with daily
snapshots, while the file for older period would have data
for a hundred days with snapshots every ten days, etc.

The implementation is optimized for fast history update and no impact
on system runtime performance and minimizing memory footprint. We
are lazily persisting state to disk on a dedicated thread as this is
slow. We are also reading the relevant historical files on a query
as this is very rare as opposed to state updates.

The base snapshot interval, i.e. snapshot time span, in the initial
iteration and the logarithmic step are configurable. These can be
changed dynamically and the history would be rewriten to take this
into account.

Test: atest CtsAppOpsTestCases

bug:111061782

Change-Id: I55c32c79911ba12b2ace58d2a782b8df1e6bff60
parent 5af6efd9
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -34374,6 +34374,8 @@ package android.os {
    method public java.util.ArrayList<java.lang.String> createStringArrayList();
    method public <T> T[] createTypedArray(android.os.Parcelable.Creator<T>);
    method public <T> java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
    method public <T extends android.os.Parcelable> android.util.ArrayMap<java.lang.String, T> createTypedArrayMap(android.os.Parcelable.Creator<T>);
    method public <T extends android.os.Parcelable> android.util.SparseArray<T> createTypedSparseArray(android.os.Parcelable.Creator<T>);
    method public int dataAvail();
    method public int dataCapacity();
    method public int dataPosition();
@@ -34415,7 +34417,7 @@ package android.os {
    method public java.io.Serializable readSerializable();
    method public android.util.Size readSize();
    method public android.util.SizeF readSizeF();
    method public android.util.SparseArray readSparseArray(java.lang.ClassLoader);
    method public <T> android.util.SparseArray<T> readSparseArray(java.lang.ClassLoader);
    method public android.util.SparseBooleanArray readSparseBooleanArray();
    method public java.lang.String readString();
    method public void readStringArray(java.lang.String[]);
@@ -34461,7 +34463,7 @@ package android.os {
    method public void writeSerializable(java.io.Serializable);
    method public void writeSize(android.util.Size);
    method public void writeSizeF(android.util.SizeF);
    method public void writeSparseArray(android.util.SparseArray<java.lang.Object>);
    method public <T> void writeSparseArray(android.util.SparseArray<T>);
    method public void writeSparseBooleanArray(android.util.SparseBooleanArray);
    method public void writeString(java.lang.String);
    method public void writeStringArray(java.lang.String[]);
@@ -34469,8 +34471,10 @@ package android.os {
    method public void writeStrongBinder(android.os.IBinder);
    method public void writeStrongInterface(android.os.IInterface);
    method public <T extends android.os.Parcelable> void writeTypedArray(T[], int);
    method public <T extends android.os.Parcelable> void writeTypedArrayMap(android.util.ArrayMap<java.lang.String, T>, int);
    method public <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
    method public <T extends android.os.Parcelable> void writeTypedObject(T, int);
    method public <T extends android.os.Parcelable> void writeTypedSparseArray(android.util.SparseArray<T>, int);
    method public void writeValue(java.lang.Object);
    field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
  }
+31 −10
Original line number Diff line number Diff line
@@ -284,10 +284,11 @@ package android.app {
  }

  public class AppOpsManager {
    method public java.util.List<android.app.AppOpsManager.HistoricalPackageOps> getAllHistoricPackagesOps(java.lang.String[], long, long);
    method public android.app.AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int, java.lang.String, java.lang.String[], long, long);
    method public void getHistoricalOps(int, java.lang.String, java.lang.String[], long, long, java.util.concurrent.Executor, java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
    method public static java.lang.String[] getOpStrs();
    method public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, java.lang.String, int[]);
    method public deprecated java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, java.lang.String, int[]);
    method public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, java.lang.String, java.lang.String...);
    method public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOps(java.lang.String[]);
    method public static int opToDefaultMode(java.lang.String);
    method public static java.lang.String opToPermission(java.lang.String);
    method public void setMode(java.lang.String, int, java.lang.String, int);
@@ -343,7 +344,7 @@ package android.app {
    field public static final int UID_STATE_TOP = 1; // 0x1
  }

  public static final class AppOpsManager.HistoricalOpEntry implements android.os.Parcelable {
  public static final class AppOpsManager.HistoricalOp implements android.os.Parcelable {
    method public int describeContents();
    method public long getAccessCount(int);
    method public long getAccessDuration(int);
@@ -353,23 +354,43 @@ package android.app {
    method public long getForegroundAccessCount();
    method public long getForegroundAccessDuration();
    method public long getForegroundRejectCount();
    method public java.lang.String getOp();
    method public java.lang.String getOpName();
    method public long getRejectCount(int);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOpEntry> CREATOR;
    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOp> CREATOR;
  }

  public static final class AppOpsManager.HistoricalOps implements android.os.Parcelable {
    method public int describeContents();
    method public long getBeginTimeMillis();
    method public long getEndTimeMillis();
    method public int getUidCount();
    method public android.app.AppOpsManager.HistoricalUidOps getUidOps(int);
    method public android.app.AppOpsManager.HistoricalUidOps getUidOpsAt(int);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOps> CREATOR;
  }

  public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
    method public int describeContents();
    method public android.app.AppOpsManager.HistoricalOpEntry getEntry(java.lang.String);
    method public android.app.AppOpsManager.HistoricalOpEntry getEntryAt(int);
    method public int getEntryCount();
    method public android.app.AppOpsManager.HistoricalOp getOp(java.lang.String);
    method public android.app.AppOpsManager.HistoricalOp getOpAt(int);
    method public int getOpCount();
    method public java.lang.String getPackageName();
    method public int getUid();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalPackageOps> CREATOR;
  }

  public static final class AppOpsManager.HistoricalUidOps implements android.os.Parcelable {
    method public int describeContents();
    method public int getPackageCount();
    method public android.app.AppOpsManager.HistoricalPackageOps getPackageOps(java.lang.String);
    method public android.app.AppOpsManager.HistoricalPackageOps getPackageOpsAt(int);
    method public int getUid();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalUidOps> CREATOR;
  }

  public static final class AppOpsManager.OpEntry implements android.os.Parcelable {
    method public int describeContents();
    method public int getDuration();
+49 −9
Original line number Diff line number Diff line
@@ -89,18 +89,26 @@ package android.app {
  }

  public class AppOpsManager {
    method public java.util.List<android.app.AppOpsManager.HistoricalPackageOps> getAllHistoricPackagesOps(java.lang.String[], long, long);
    method public android.app.AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int, java.lang.String, java.lang.String[], long, long);
    method public void addHistoricalOps(android.app.AppOpsManager.HistoricalOps);
    method public void clearHistory();
    method public void getHistoricalOps(int, java.lang.String, java.lang.String[], long, long, java.util.concurrent.Executor, java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
    method public void getHistoricalOpsFromDiskRaw(int, java.lang.String, java.lang.String[], long, long, java.util.concurrent.Executor, java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
    method public static int getNumOps();
    method public static java.lang.String[] getOpStrs();
    method public boolean isOperationActive(int, int, java.lang.String);
    method public void offsetHistory(long);
    method public static java.lang.String opToPermission(int);
    method public static int permissionToOpCode(java.lang.String);
    method public void resetHistoryParameters();
    method public void setHistoryParameters(int, long, int);
    method public void setMode(int, int, java.lang.String, int);
    method public void setUidMode(java.lang.String, int, int);
    method public void startWatchingActive(int[], android.app.AppOpsManager.OnOpActiveChangedListener);
    method public void stopWatchingActive(android.app.AppOpsManager.OnOpActiveChangedListener);
    method public static int strOpToOp(java.lang.String);
    field public static final int HISTORICAL_MODE_DISABLED = 0; // 0x0
    field public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1; // 0x1
    field public static final int HISTORICAL_MODE_ENABLED_PASSIVE = 2; // 0x2
    field public static final java.lang.String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
    field public static final java.lang.String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
    field public static final java.lang.String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
@@ -144,11 +152,18 @@ package android.app {
    field public static final java.lang.String OPSTR_WRITE_ICC_SMS = "android:write_icc_sms";
    field public static final java.lang.String OPSTR_WRITE_SMS = "android:write_sms";
    field public static final java.lang.String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper";
    field public static final int OP_COARSE_LOCATION = 0; // 0x0
    field public static final int OP_RECORD_AUDIO = 27; // 0x1b
    field public static final int OP_SYSTEM_ALERT_WINDOW = 24; // 0x18
    field public static final int UID_STATE_BACKGROUND = 4; // 0x4
    field public static final int UID_STATE_CACHED = 5; // 0x5
    field public static final int UID_STATE_FOREGROUND = 3; // 0x3
    field public static final int UID_STATE_FOREGROUND_SERVICE = 2; // 0x2
    field public static final int UID_STATE_PERSISTENT = 0; // 0x0
    field public static final int UID_STATE_TOP = 1; // 0x1
  }

  public static final class AppOpsManager.HistoricalOpEntry implements android.os.Parcelable {
  public static final class AppOpsManager.HistoricalOp implements android.os.Parcelable {
    method public int describeContents();
    method public long getAccessCount(int);
    method public long getAccessDuration(int);
@@ -158,23 +173,48 @@ package android.app {
    method public long getForegroundAccessCount();
    method public long getForegroundAccessDuration();
    method public long getForegroundRejectCount();
    method public java.lang.String getOp();
    method public java.lang.String getOpName();
    method public long getRejectCount(int);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOpEntry> CREATOR;
    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOp> CREATOR;
  }

  public static final class AppOpsManager.HistoricalOps implements android.os.Parcelable {
    ctor public AppOpsManager.HistoricalOps(long, long);
    method public int describeContents();
    method public long getBeginTimeMillis();
    method public long getEndTimeMillis();
    method public int getUidCount();
    method public android.app.AppOpsManager.HistoricalUidOps getUidOps(int);
    method public android.app.AppOpsManager.HistoricalUidOps getUidOpsAt(int);
    method public void increaseAccessCount(int, int, java.lang.String, int, long);
    method public void increaseAccessDuration(int, int, java.lang.String, int, long);
    method public void increaseRejectCount(int, int, java.lang.String, int, long);
    method public void offsetBeginAndEndTime(long);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOps> CREATOR;
  }

  public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
    method public int describeContents();
    method public android.app.AppOpsManager.HistoricalOpEntry getEntry(java.lang.String);
    method public android.app.AppOpsManager.HistoricalOpEntry getEntryAt(int);
    method public int getEntryCount();
    method public android.app.AppOpsManager.HistoricalOp getOp(java.lang.String);
    method public android.app.AppOpsManager.HistoricalOp getOpAt(int);
    method public int getOpCount();
    method public java.lang.String getPackageName();
    method public int getUid();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalPackageOps> CREATOR;
  }

  public static final class AppOpsManager.HistoricalUidOps implements android.os.Parcelable {
    method public int describeContents();
    method public int getPackageCount();
    method public android.app.AppOpsManager.HistoricalPackageOps getPackageOps(java.lang.String);
    method public android.app.AppOpsManager.HistoricalPackageOps getPackageOpsAt(int);
    method public int getUid();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalUidOps> CREATOR;
  }

  public static abstract interface AppOpsManager.OnOpActiveChangedListener {
    method public abstract void onOpActiveChanged(int, int, java.lang.String, boolean);
  }
+3 −1
Original line number Diff line number Diff line
@@ -19,5 +19,7 @@ package android.app;
parcelable AppOpsManager.PackageOps;
parcelable AppOpsManager.OpEntry;

parcelable AppOpsManager.HistoricalOp;
parcelable AppOpsManager.HistoricalOps;
parcelable AppOpsManager.HistoricalPackageOps;
parcelable AppOpsManager.HistoricalOpEntry;
parcelable AppOpsManager.HistoricalUidOps;
+1543 −274

File changed.

Preview size limit exceeded, changes collapsed.

Loading