Loading services/core/java/com/android/server/appop/AppOpsService.java +30 −4 Original line number Diff line number Diff line Loading @@ -5276,8 +5276,12 @@ public class AppOpsService extends IAppOpsService.Stub { pw.println(" Limit output to data associated with the given package name."); pw.println(" --attributionTag [attributionTag]"); pw.println(" Limit output to data associated with the given attribution tag."); pw.println(" --include-discrete [n]"); pw.println(" Include discrete ops limited to n per dimension. Use zero for no limit."); pw.println(" --watchers"); pw.println(" Only output the watcher sections."); pw.println(" --history"); pw.println(" Only output history."); } private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterAttributionTag, Loading Loading @@ -5412,6 +5416,8 @@ public class AppOpsService extends IAppOpsService.Stub { boolean dumpWatchers = false; // TODO ntmyren: Remove the dumpHistory and dumpFilter boolean dumpHistory = false; boolean includeDiscreteOps = false; int nDiscreteOps = 10; @HistoricalOpsRequestFilter int dumpFilter = 0; if (args != null) { Loading Loading @@ -5473,6 +5479,21 @@ public class AppOpsService extends IAppOpsService.Stub { } } else if ("--watchers".equals(arg)) { dumpWatchers = true; } else if ("--include-discrete".equals(arg)) { i++; if (i >= args.length) { pw.println("No argument for --include-discrete option"); return; } try { nDiscreteOps = Integer.valueOf(args[i]); } catch (NumberFormatException e) { pw.println("Wrong parameter: " + args[i]); return; } includeDiscreteOps = true; } else if ("--history".equals(arg)) { dumpHistory = true; } else if (arg.length() > 0 && arg.charAt(0) == '-') { pw.println("Unknown option: " + arg); return; Loading @@ -5483,6 +5504,8 @@ public class AppOpsService extends IAppOpsService.Stub { } } final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); final Date date = new Date(); synchronized (this) { pw.println("Current AppOps Service state:"); if (!dumpHistory && !dumpWatchers) { Loading @@ -5492,8 +5515,6 @@ public class AppOpsService extends IAppOpsService.Stub { final long now = System.currentTimeMillis(); final long nowElapsed = SystemClock.elapsedRealtime(); final long nowUptime = SystemClock.uptimeMillis(); final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); final Date date = new Date(); boolean needSep = false; if (dumpFilter == 0 && dumpMode < 0 && mProfileOwners != null && !dumpWatchers && !dumpHistory) { Loading Loading @@ -5961,6 +5982,11 @@ public class AppOpsService extends IAppOpsService.Stub { mHistoricalRegistry.dump(" ", pw, dumpUid, dumpPackage, dumpAttributionTag, dumpOp, dumpFilter); } if (includeDiscreteOps) { pw.println("Discrete accesses: "); mHistoricalRegistry.dumpDiscreteData(pw, dumpUid, dumpPackage, dumpAttributionTag, dumpFilter, dumpOp, sdf, date, " ", nDiscreteOps); } } @Override Loading services/core/java/com/android/server/appop/DiscreteRegistry.java +97 −0 Original line number Diff line number Diff line Loading @@ -23,9 +23,13 @@ import static android.app.AppOpsManager.FILTER_BY_UID; import static android.app.AppOpsManager.OP_CAMERA; import static android.app.AppOpsManager.OP_COARSE_LOCATION; import static android.app.AppOpsManager.OP_FINE_LOCATION; import static android.app.AppOpsManager.OP_FLAGS_ALL; import static android.app.AppOpsManager.OP_FLAG_SELF; import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED; import static android.app.AppOpsManager.OP_NONE; import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.app.AppOpsManager.flagsToString; import static android.app.AppOpsManager.getUidStateName; import static java.lang.Math.max; Loading @@ -45,15 +49,20 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import com.android.internal.util.XmlUtils; import libcore.util.EmptyArray; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; /** Loading Loading @@ -237,6 +246,23 @@ final class DiscreteRegistry { } } void dump(@NonNull PrintWriter pw, int uidFilter, @Nullable String packageNameFilter, @Nullable String attributionTagFilter, @AppOpsManager.HistoricalOpsRequestFilter int filter, int dumpOp, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, int nDiscreteOps) { DiscreteOps discreteOps = new DiscreteOps(); synchronized (mOnDiskLock) { writeAndClearAccessHistory(); String[] opNamesFilter = dumpOp == OP_NONE ? EmptyArray.STRING : new String[]{AppOpsManager.opToPublicName(dumpOp)}; readDiscreteOpsFromDisk(discreteOps, 0, Instant.now().toEpochMilli(), filter, uidFilter, packageNameFilter, opNamesFilter, attributionTagFilter, OP_FLAGS_ALL); } discreteOps.dump(pw, sdf, date, prefix, nDiscreteOps); } public static boolean isDiscreteOp(int op, int uid, @AppOpsManager.OpFlags int flags) { if (!isDiscreteOp(op)) { return false; Loading Loading @@ -306,6 +332,18 @@ final class DiscreteRegistry { stream.close(); } private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, int nDiscreteOps) { int nUids = mUids.size(); for (int i = 0; i < nUids; i++) { pw.print(prefix); pw.print("Uid: "); pw.print(mUids.keyAt(i)); pw.println(); mUids.valueAt(i).dump(pw, sdf, date, prefix + " ", nDiscreteOps); } } private DiscreteUidOps getOrCreateDiscreteUidOps(int uid) { DiscreteUidOps result = mUids.get(uid); if (result == null) { Loading Loading @@ -395,6 +433,18 @@ final class DiscreteRegistry { } } private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, int nDiscreteOps) { int nPackages = mPackages.size(); for (int i = 0; i < nPackages; i++) { pw.print(prefix); pw.print("Package: "); pw.print(mPackages.keyAt(i)); pw.println(); mPackages.valueAt(i).dump(pw, sdf, date, prefix + " ", nDiscreteOps); } } void deserialize(TypedXmlPullParser parser, long beginTimeMillis, long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, @Nullable String packageNameFilter, Loading Loading @@ -458,6 +508,17 @@ final class DiscreteRegistry { } } private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, int nDiscreteOps) { int nOps = mPackageOps.size(); for (int i = 0; i < nOps; i++) { pw.print(prefix); pw.print(AppOpsManager.opToName(mPackageOps.keyAt(i))); pw.println(); mPackageOps.valueAt(i).dump(pw, sdf, date, prefix + " ", nDiscreteOps); } } void deserialize(TypedXmlPullParser parser, long beginTimeMillis, long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter, Loading Loading @@ -535,6 +596,24 @@ final class DiscreteRegistry { } } private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, int nDiscreteOps) { int nAttributions = mAttributedOps.size(); for (int i = 0; i < nAttributions; i++) { pw.print(prefix); pw.print("Attribution: "); pw.print(mAttributedOps.keyAt(i)); pw.println(); List<DiscreteOpEvent> ops = mAttributedOps.valueAt(i); int nOps = ops.size(); int first = nDiscreteOps < 1 ? 0 : max(0, nOps - nDiscreteOps); for (int j = first; j < nOps; j++) { ops.get(j).dump(pw, sdf, date, prefix + " "); } } } void serialize(TypedXmlSerializer out) throws Exception { int nAttributions = mAttributedOps.size(); for (int i = 0; i < nAttributions; i++) { Loading Loading @@ -609,6 +688,24 @@ final class DiscreteRegistry { mOpFlag = opFlag; } private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix) { pw.print(prefix); pw.print("Access ["); pw.print(getUidStateName(mUidState)); pw.print("-"); pw.print(flagsToString(mOpFlag)); pw.print("] at "); date.setTime(mNoteTime); pw.print(sdf.format(date)); if (mNoteDuration != -1) { pw.print(" for "); pw.print(mNoteDuration); pw.print(" milliseconds "); } pw.println(); } private void serialize(TypedXmlSerializer out) throws Exception { out.attributeLong(null, ATTR_NOTE_TIME, mNoteTime); if (mNoteDuration != -1) { Loading services/core/java/com/android/server/appop/HistoricalRegistry.java +9 −0 Original line number Diff line number Diff line Loading @@ -349,6 +349,15 @@ final class HistoricalRegistry { } } void dumpDiscreteData(@NonNull PrintWriter pw, int uidFilter, @Nullable String packageNameFilter, @Nullable String attributionTagFilter, @HistoricalOpsRequestFilter int filter, int dumpOp, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, int nDiscreteOps) { mDiscreteRegistry.dump(pw, uidFilter, packageNameFilter, attributionTagFilter, filter, dumpOp, sdf, date, prefix, nDiscreteOps); } @HistoricalMode int getMode() { synchronized (mInMemoryLock) { return mMode; Loading Loading
services/core/java/com/android/server/appop/AppOpsService.java +30 −4 Original line number Diff line number Diff line Loading @@ -5276,8 +5276,12 @@ public class AppOpsService extends IAppOpsService.Stub { pw.println(" Limit output to data associated with the given package name."); pw.println(" --attributionTag [attributionTag]"); pw.println(" Limit output to data associated with the given attribution tag."); pw.println(" --include-discrete [n]"); pw.println(" Include discrete ops limited to n per dimension. Use zero for no limit."); pw.println(" --watchers"); pw.println(" Only output the watcher sections."); pw.println(" --history"); pw.println(" Only output history."); } private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterAttributionTag, Loading Loading @@ -5412,6 +5416,8 @@ public class AppOpsService extends IAppOpsService.Stub { boolean dumpWatchers = false; // TODO ntmyren: Remove the dumpHistory and dumpFilter boolean dumpHistory = false; boolean includeDiscreteOps = false; int nDiscreteOps = 10; @HistoricalOpsRequestFilter int dumpFilter = 0; if (args != null) { Loading Loading @@ -5473,6 +5479,21 @@ public class AppOpsService extends IAppOpsService.Stub { } } else if ("--watchers".equals(arg)) { dumpWatchers = true; } else if ("--include-discrete".equals(arg)) { i++; if (i >= args.length) { pw.println("No argument for --include-discrete option"); return; } try { nDiscreteOps = Integer.valueOf(args[i]); } catch (NumberFormatException e) { pw.println("Wrong parameter: " + args[i]); return; } includeDiscreteOps = true; } else if ("--history".equals(arg)) { dumpHistory = true; } else if (arg.length() > 0 && arg.charAt(0) == '-') { pw.println("Unknown option: " + arg); return; Loading @@ -5483,6 +5504,8 @@ public class AppOpsService extends IAppOpsService.Stub { } } final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); final Date date = new Date(); synchronized (this) { pw.println("Current AppOps Service state:"); if (!dumpHistory && !dumpWatchers) { Loading @@ -5492,8 +5515,6 @@ public class AppOpsService extends IAppOpsService.Stub { final long now = System.currentTimeMillis(); final long nowElapsed = SystemClock.elapsedRealtime(); final long nowUptime = SystemClock.uptimeMillis(); final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); final Date date = new Date(); boolean needSep = false; if (dumpFilter == 0 && dumpMode < 0 && mProfileOwners != null && !dumpWatchers && !dumpHistory) { Loading Loading @@ -5961,6 +5982,11 @@ public class AppOpsService extends IAppOpsService.Stub { mHistoricalRegistry.dump(" ", pw, dumpUid, dumpPackage, dumpAttributionTag, dumpOp, dumpFilter); } if (includeDiscreteOps) { pw.println("Discrete accesses: "); mHistoricalRegistry.dumpDiscreteData(pw, dumpUid, dumpPackage, dumpAttributionTag, dumpFilter, dumpOp, sdf, date, " ", nDiscreteOps); } } @Override Loading
services/core/java/com/android/server/appop/DiscreteRegistry.java +97 −0 Original line number Diff line number Diff line Loading @@ -23,9 +23,13 @@ import static android.app.AppOpsManager.FILTER_BY_UID; import static android.app.AppOpsManager.OP_CAMERA; import static android.app.AppOpsManager.OP_COARSE_LOCATION; import static android.app.AppOpsManager.OP_FINE_LOCATION; import static android.app.AppOpsManager.OP_FLAGS_ALL; import static android.app.AppOpsManager.OP_FLAG_SELF; import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED; import static android.app.AppOpsManager.OP_NONE; import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.app.AppOpsManager.flagsToString; import static android.app.AppOpsManager.getUidStateName; import static java.lang.Math.max; Loading @@ -45,15 +49,20 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import com.android.internal.util.XmlUtils; import libcore.util.EmptyArray; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; /** Loading Loading @@ -237,6 +246,23 @@ final class DiscreteRegistry { } } void dump(@NonNull PrintWriter pw, int uidFilter, @Nullable String packageNameFilter, @Nullable String attributionTagFilter, @AppOpsManager.HistoricalOpsRequestFilter int filter, int dumpOp, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, int nDiscreteOps) { DiscreteOps discreteOps = new DiscreteOps(); synchronized (mOnDiskLock) { writeAndClearAccessHistory(); String[] opNamesFilter = dumpOp == OP_NONE ? EmptyArray.STRING : new String[]{AppOpsManager.opToPublicName(dumpOp)}; readDiscreteOpsFromDisk(discreteOps, 0, Instant.now().toEpochMilli(), filter, uidFilter, packageNameFilter, opNamesFilter, attributionTagFilter, OP_FLAGS_ALL); } discreteOps.dump(pw, sdf, date, prefix, nDiscreteOps); } public static boolean isDiscreteOp(int op, int uid, @AppOpsManager.OpFlags int flags) { if (!isDiscreteOp(op)) { return false; Loading Loading @@ -306,6 +332,18 @@ final class DiscreteRegistry { stream.close(); } private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, int nDiscreteOps) { int nUids = mUids.size(); for (int i = 0; i < nUids; i++) { pw.print(prefix); pw.print("Uid: "); pw.print(mUids.keyAt(i)); pw.println(); mUids.valueAt(i).dump(pw, sdf, date, prefix + " ", nDiscreteOps); } } private DiscreteUidOps getOrCreateDiscreteUidOps(int uid) { DiscreteUidOps result = mUids.get(uid); if (result == null) { Loading Loading @@ -395,6 +433,18 @@ final class DiscreteRegistry { } } private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, int nDiscreteOps) { int nPackages = mPackages.size(); for (int i = 0; i < nPackages; i++) { pw.print(prefix); pw.print("Package: "); pw.print(mPackages.keyAt(i)); pw.println(); mPackages.valueAt(i).dump(pw, sdf, date, prefix + " ", nDiscreteOps); } } void deserialize(TypedXmlPullParser parser, long beginTimeMillis, long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, @Nullable String packageNameFilter, Loading Loading @@ -458,6 +508,17 @@ final class DiscreteRegistry { } } private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, int nDiscreteOps) { int nOps = mPackageOps.size(); for (int i = 0; i < nOps; i++) { pw.print(prefix); pw.print(AppOpsManager.opToName(mPackageOps.keyAt(i))); pw.println(); mPackageOps.valueAt(i).dump(pw, sdf, date, prefix + " ", nDiscreteOps); } } void deserialize(TypedXmlPullParser parser, long beginTimeMillis, long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter, Loading Loading @@ -535,6 +596,24 @@ final class DiscreteRegistry { } } private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, int nDiscreteOps) { int nAttributions = mAttributedOps.size(); for (int i = 0; i < nAttributions; i++) { pw.print(prefix); pw.print("Attribution: "); pw.print(mAttributedOps.keyAt(i)); pw.println(); List<DiscreteOpEvent> ops = mAttributedOps.valueAt(i); int nOps = ops.size(); int first = nDiscreteOps < 1 ? 0 : max(0, nOps - nDiscreteOps); for (int j = first; j < nOps; j++) { ops.get(j).dump(pw, sdf, date, prefix + " "); } } } void serialize(TypedXmlSerializer out) throws Exception { int nAttributions = mAttributedOps.size(); for (int i = 0; i < nAttributions; i++) { Loading Loading @@ -609,6 +688,24 @@ final class DiscreteRegistry { mOpFlag = opFlag; } private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix) { pw.print(prefix); pw.print("Access ["); pw.print(getUidStateName(mUidState)); pw.print("-"); pw.print(flagsToString(mOpFlag)); pw.print("] at "); date.setTime(mNoteTime); pw.print(sdf.format(date)); if (mNoteDuration != -1) { pw.print(" for "); pw.print(mNoteDuration); pw.print(" milliseconds "); } pw.println(); } private void serialize(TypedXmlSerializer out) throws Exception { out.attributeLong(null, ATTR_NOTE_TIME, mNoteTime); if (mNoteDuration != -1) { Loading
services/core/java/com/android/server/appop/HistoricalRegistry.java +9 −0 Original line number Diff line number Diff line Loading @@ -349,6 +349,15 @@ final class HistoricalRegistry { } } void dumpDiscreteData(@NonNull PrintWriter pw, int uidFilter, @Nullable String packageNameFilter, @Nullable String attributionTagFilter, @HistoricalOpsRequestFilter int filter, int dumpOp, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix, int nDiscreteOps) { mDiscreteRegistry.dump(pw, uidFilter, packageNameFilter, attributionTagFilter, filter, dumpOp, sdf, date, prefix, nDiscreteOps); } @HistoricalMode int getMode() { synchronized (mInMemoryLock) { return mMode; Loading