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

Commit f78c7162 authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "Add boot session stable sampling to AppFeaturesOps puller." into...

Merge "Add boot session stable sampling to AppFeaturesOps puller." into rvc-dev am: 3eae8652 am: 816b5106

Change-Id: I4e9e311e19e9c5ce904f786ad5969a8dc361cf8c
parents 2513c1fb 816b5106
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -7640,6 +7640,9 @@ message AppFeaturesOps {


    // Whether AppOps is guarded by Runtime permission
    // Whether AppOps is guarded by Runtime permission
    optional bool is_runtime_permission = 11;
    optional bool is_runtime_permission = 11;

    // Sampling rate used on device, from 0 to 100
    optional int32 sampling_rate = 12;
}
}


/**
/**
+116 −80
Original line number Original line Diff line number Diff line
@@ -24,6 +24,8 @@ import static android.os.Debug.getIonHeapsSizeKb;
import static android.os.Process.getUidForPid;
import static android.os.Process.getUidForPid;
import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
import static android.util.MathUtils.abs;
import static android.util.MathUtils.constrain;


import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
@@ -146,12 +148,15 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStream;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
import java.util.HashSet;
import java.util.HashSet;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.MissingResourceException;
import java.util.Random;
import java.util.Set;
import java.util.Set;
import java.util.UUID;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletableFuture;
@@ -169,6 +174,9 @@ public class StatsPullAtomService extends SystemService {
    private static final String TAG = "StatsPullAtomService";
    private static final String TAG = "StatsPullAtomService";
    private static final boolean DEBUG = true;
    private static final boolean DEBUG = true;


    // Random seed stable for StatsPullAtomService life cycle - can be used for stable sampling
    private static final int RANDOM_SEED = new Random().nextInt();

    /**
    /**
     * Lowest available uid for apps.
     * Lowest available uid for apps.
     *
     *
@@ -256,6 +264,8 @@ public class StatsPullAtomService extends SystemService {


    private StatsPullAtomCallbackImpl mStatsCallbackImpl;
    private StatsPullAtomCallbackImpl mStatsCallbackImpl;


    private int mAppOpsSamplingRate = 0;

    public StatsPullAtomService(Context context) {
    public StatsPullAtomService(Context context) {
        super(context);
        super(context);
        mContext = context;
        mContext = context;
@@ -2877,44 +2887,7 @@ public class StatsPullAtomService extends SystemService {


            HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
            HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
                    TimeUnit.MILLISECONDS);
                    TimeUnit.MILLISECONDS);

            processHistoricalOps(histOps, atomTag, pulledData);
            for (int uidIdx = 0; uidIdx < histOps.getUidCount(); uidIdx++) {
                final HistoricalUidOps uidOps = histOps.getUidOpsAt(uidIdx);
                final int uid = uidOps.getUid();
                for (int pkgIdx = 0; pkgIdx < uidOps.getPackageCount(); pkgIdx++) {
                    final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(pkgIdx);
                    for (int opIdx = 0; opIdx < packageOps.getOpCount(); opIdx++) {
                        final AppOpsManager.HistoricalOp op = packageOps.getOpAt(opIdx);

                        StatsEvent.Builder e = StatsEvent.newBuilder();
                        e.setAtomId(atomTag);
                        e.writeInt(uid);
                        e.writeString(packageOps.getPackageName());
                        e.writeInt(op.getOpCode());
                        e.writeLong(op.getForegroundAccessCount(OP_FLAGS_PULLED));
                        e.writeLong(op.getBackgroundAccessCount(OP_FLAGS_PULLED));
                        e.writeLong(op.getForegroundRejectCount(OP_FLAGS_PULLED));
                        e.writeLong(op.getBackgroundRejectCount(OP_FLAGS_PULLED));
                        e.writeLong(op.getForegroundAccessDuration(OP_FLAGS_PULLED));
                        e.writeLong(op.getBackgroundAccessDuration(OP_FLAGS_PULLED));

                        String perm = AppOpsManager.opToPermission(op.getOpCode());
                        if (perm == null) {
                            e.writeBoolean(false);
                        } else {
                            PermissionInfo permInfo;
                            try {
                                permInfo = mContext.getPackageManager().getPermissionInfo(perm, 0);
                                e.writeBoolean(permInfo.getProtection() == PROTECTION_DANGEROUS);
                            } catch (PackageManager.NameNotFoundException exception) {
                                e.writeBoolean(false);
                            }
                        }

                        pulledData.add(e.build());
                    }
                }
            }
        } catch (Throwable t) {
        } catch (Throwable t) {
            // TODO: catch exceptions at a more granular level
            // TODO: catch exceptions at a more granular level
            Slog.e(TAG, "Could not read appops", t);
            Slog.e(TAG, "Could not read appops", t);
@@ -2945,27 +2918,98 @@ public class StatsPullAtomService extends SystemService {
                    new HistoricalOpsRequest.Builder(0, Long.MAX_VALUE).setFlags(
                    new HistoricalOpsRequest.Builder(0, Long.MAX_VALUE).setFlags(
                            OP_FLAGS_PULLED).build();
                            OP_FLAGS_PULLED).build();
            appOps.getHistoricalOps(histOpsRequest, mContext.getMainExecutor(), ops::complete);
            appOps.getHistoricalOps(histOpsRequest, mContext.getMainExecutor(), ops::complete);
            HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
                    TimeUnit.MILLISECONDS);
            if (mAppOpsSamplingRate == 0) {
                mAppOpsSamplingRate = constrain((5000 * 100) / estimateAppOpsSize(), 1, 100);
            }
            processHistoricalOps(histOps, atomTag, pulledData);
        } catch (Throwable t) {
            // TODO: catch exceptions at a more granular level
            Slog.e(TAG, "Could not read appops", t);
            return StatsManager.PULL_SKIP;
        } finally {
            Binder.restoreCallingIdentity(token);
        }
        return StatsManager.PULL_SUCCESS;
    }

    private int estimateAppOpsSize() throws Exception {
        AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);


        CompletableFuture<HistoricalOps> ops = new CompletableFuture<>();
        HistoricalOpsRequest histOpsRequest =
                new HistoricalOpsRequest.Builder(
                        Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli(),
                        Long.MAX_VALUE).setFlags(
                        OP_FLAGS_PULLED).build();
        appOps.getHistoricalOps(histOpsRequest, mContext.getMainExecutor(), ops::complete);
        HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
        HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
                TimeUnit.MILLISECONDS);
                TimeUnit.MILLISECONDS);
        return processHistoricalOps(histOps, FrameworkStatsLog.APP_FEATURES_OPS, null);
    }


    int processHistoricalOps(HistoricalOps histOps, int atomTag, List<StatsEvent> pulledData) {
        int counter = 0;
        for (int uidIdx = 0; uidIdx < histOps.getUidCount(); uidIdx++) {
        for (int uidIdx = 0; uidIdx < histOps.getUidCount(); uidIdx++) {
            final HistoricalUidOps uidOps = histOps.getUidOpsAt(uidIdx);
            final HistoricalUidOps uidOps = histOps.getUidOpsAt(uidIdx);
            final int uid = uidOps.getUid();
            final int uid = uidOps.getUid();
            for (int pkgIdx = 0; pkgIdx < uidOps.getPackageCount(); pkgIdx++) {
            for (int pkgIdx = 0; pkgIdx < uidOps.getPackageCount(); pkgIdx++) {
                final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(pkgIdx);
                final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(pkgIdx);
                if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
                    for (int featureIdx = 0; featureIdx < packageOps.getFeatureCount();
                    for (int featureIdx = 0; featureIdx < packageOps.getFeatureCount();
                            featureIdx++) {
                            featureIdx++) {
                        final AppOpsManager.HistoricalFeatureOps featureOps =
                        final AppOpsManager.HistoricalFeatureOps featureOps =
                                packageOps.getFeatureOpsAt(featureIdx);
                                packageOps.getFeatureOpsAt(featureIdx);
                        for (int opIdx = 0; opIdx < featureOps.getOpCount(); opIdx++) {
                        for (int opIdx = 0; opIdx < featureOps.getOpCount(); opIdx++) {
                            final AppOpsManager.HistoricalOp op = featureOps.getOpAt(opIdx);
                            final AppOpsManager.HistoricalOp op = featureOps.getOpAt(opIdx);
                            counter += processHistoricalOp(op, atomTag, pulledData, uid,
                                    packageOps.getPackageName(), featureOps.getFeatureId());
                        }
                    }
                } else if (atomTag == FrameworkStatsLog.APP_OPS) {
                    for (int opIdx = 0; opIdx < packageOps.getOpCount(); opIdx++) {
                        final AppOpsManager.HistoricalOp op = packageOps.getOpAt(opIdx);
                        counter += processHistoricalOp(op, atomTag, pulledData, uid,
                                packageOps.getPackageName(), null);
                    }
                }
            }
        }
        return counter;
    }

    private int processHistoricalOp(AppOpsManager.HistoricalOp op, int atomTag,
            @Nullable List<StatsEvent> pulledData, int uid, String packageName,
            @Nullable String feature) {
        if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
            if (pulledData == null) { // this is size estimation call
                if (op.getForegroundAccessCount(OP_FLAGS_PULLED) + op.getBackgroundAccessCount(
                        OP_FLAGS_PULLED) == 0) {
                    return 0;
                } else {
                    return 32 + packageName.length() + (feature == null ? 1 : feature.length());
                }
            } else {
                if (abs((op.getOpCode() + feature + packageName).hashCode() + RANDOM_SEED) % 100
                        >= mAppOpsSamplingRate) {
                    return 0;
                }
            }
        }

        StatsEvent.Builder e = StatsEvent.newBuilder();
        StatsEvent.Builder e = StatsEvent.newBuilder();
        e.setAtomId(atomTag);
        e.setAtomId(atomTag);
        e.writeInt(uid);
        e.writeInt(uid);
                            e.writeString(packageOps.getPackageName());
        e.writeString(packageName);
                            e.writeString(featureOps.getFeatureId());
        if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
            e.writeString(feature);
        }
        if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
            e.writeString(op.getOpName());
            e.writeString(op.getOpName());
        } else {
            e.writeInt(op.getOpCode());
        }
        e.writeLong(op.getForegroundAccessCount(OP_FLAGS_PULLED));
        e.writeLong(op.getForegroundAccessCount(OP_FLAGS_PULLED));
        e.writeLong(op.getBackgroundAccessCount(OP_FLAGS_PULLED));
        e.writeLong(op.getBackgroundAccessCount(OP_FLAGS_PULLED));
        e.writeLong(op.getForegroundRejectCount(OP_FLAGS_PULLED));
        e.writeLong(op.getForegroundRejectCount(OP_FLAGS_PULLED));
@@ -2979,7 +3023,8 @@ public class StatsPullAtomService extends SystemService {
        } else {
        } else {
            PermissionInfo permInfo;
            PermissionInfo permInfo;
            try {
            try {
                                    permInfo = mContext.getPackageManager().getPermissionInfo(perm,
                permInfo = mContext.getPackageManager().getPermissionInfo(
                        perm,
                        0);
                        0);
                e.writeBoolean(
                e.writeBoolean(
                        permInfo.getProtection() == PROTECTION_DANGEROUS);
                        permInfo.getProtection() == PROTECTION_DANGEROUS);
@@ -2987,20 +3032,11 @@ public class StatsPullAtomService extends SystemService {
                e.writeBoolean(false);
                e.writeBoolean(false);
            }
            }
        }
        }
                            pulledData.add(e.build());
        if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
                        }
            e.writeInt(mAppOpsSamplingRate);

                    }
        }
        }
            }
        pulledData.add(e.build());
        } catch (Throwable t) {
        return 0;
            // TODO: catch exceptions at a more granular level
            Slog.e(TAG, "Could not read appops", t);
            return StatsManager.PULL_SKIP;
        } finally {
            Binder.restoreCallingIdentity(token);
        }
        return StatsManager.PULL_SUCCESS;
    }
    }


    int pullRuntimeAppOpAccessMessage(int atomTag, List<StatsEvent> pulledData) {
    int pullRuntimeAppOpAccessMessage(int atomTag, List<StatsEvent> pulledData) {