aboutsummaryrefslogtreecommitdiff
path: root/java/com/android/modules
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android/modules')
-rw-r--r--java/com/android/modules/expresslog/Android.bp39
-rw-r--r--java/com/android/modules/expresslog/Counter.java67
-rw-r--r--java/com/android/modules/expresslog/Histogram.java227
-rw-r--r--java/com/android/modules/expresslog/OWNERS10
-rw-r--r--java/com/android/modules/expresslog/TEST_MAPPING12
-rw-r--r--java/com/android/modules/expresslog/Utils.java21
6 files changed, 376 insertions, 0 deletions
diff --git a/java/com/android/modules/expresslog/Android.bp b/java/com/android/modules/expresslog/Android.bp
new file mode 100644
index 0000000..cacc7f8
--- /dev/null
+++ b/java/com/android/modules/expresslog/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_library {
+ name: "modules-utils-expresslog",
+ defaults: ["modules-utils-defaults"],
+ min_sdk_version: "30",
+ srcs: [
+ "*.java",
+ ":statslog-expresslog-java-gen",
+ ],
+ libs: [
+ "framework-statsd",
+ ],
+}
+
+genrule {
+ name: "statslog-expresslog-java-gen",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --java $(out) --module expresslog" +
+ " --javaPackage com.android.modules.expresslog --javaClass StatsExpressLog",
+ out: ["com/android/modules/expresslog/StatsExpressLog.java"],
+}
diff --git a/java/com/android/modules/expresslog/Counter.java b/java/com/android/modules/expresslog/Counter.java
new file mode 100644
index 0000000..b788c3f
--- /dev/null
+++ b/java/com/android/modules/expresslog/Counter.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.modules.expresslog;
+
+import android.annotation.NonNull;
+
+import com.android.modules.expresslog.StatsExpressLog;
+
+/** Counter encapsulates StatsD write API calls */
+public final class Counter {
+
+ // Not instantiable.
+ private Counter() {}
+
+ /**
+ * Increments Telemetry Express Counter metric by 1
+ * @param metricId to log, no-op if metricId is not defined in the TeX catalog
+ */
+ public static void logIncrement(@NonNull String metricId) {
+ logIncrement(metricId, 1);
+ }
+
+ /**
+ * Increments Telemetry Express Counter metric by 1
+ * @param metricId to log, no-op if metricId is not defined in the TeX catalog
+ * @param uid used as a dimension for the count metric
+ */
+ public static void logIncrementWithUid(@NonNull String metricId, int uid) {
+ logIncrementWithUid(metricId, uid, 1);
+ }
+
+ /**
+ * Increments Telemetry Express Counter metric by arbitrary value
+ * @param metricId to log, no-op if metricId is not defined in the TeX catalog
+ * @param amount to increment counter
+ */
+ public static void logIncrement(@NonNull String metricId, long amount) {
+ final long metricIdHash = Utils.hashString(metricId);
+ StatsExpressLog.write(StatsExpressLog.EXPRESS_EVENT_REPORTED, metricIdHash, amount);
+ }
+
+ /**
+ * Increments Telemetry Express Counter metric by arbitrary value
+ * @param metricId to log, no-op if metricId is not defined in the TeX catalog
+ * @param uid used as a dimension for the count metric
+ * @param amount to increment counter
+ */
+ public static void logIncrementWithUid(@NonNull String metricId, int uid, long amount) {
+ final long metricIdHash = Utils.hashString(metricId);
+ StatsExpressLog.write(
+ StatsExpressLog.EXPRESS_UID_EVENT_REPORTED, metricIdHash, amount, uid);
+ }
+}
diff --git a/java/com/android/modules/expresslog/Histogram.java b/java/com/android/modules/expresslog/Histogram.java
new file mode 100644
index 0000000..be300bf
--- /dev/null
+++ b/java/com/android/modules/expresslog/Histogram.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.modules.expresslog;
+
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+
+import com.android.modules.expresslog.StatsExpressLog;
+
+import java.util.Arrays;
+
+/** Histogram encapsulates StatsD write API calls */
+public final class Histogram {
+
+ private final long mMetricIdHash;
+ private final BinOptions mBinOptions;
+
+ /**
+ * Creates Histogram metric logging wrapper
+ *
+ * @param metricId to log, logging will be no-op if metricId is not defined in the TeX catalog
+ * @param binOptions to calculate bin index for samples
+ */
+ public Histogram(@NonNull String metricId, @NonNull BinOptions binOptions) {
+ mMetricIdHash = Utils.hashString(metricId);
+ mBinOptions = binOptions;
+ }
+
+ /**
+ * Logs increment sample count for automatically calculated bin
+ *
+ * @param sample value
+ */
+ public void logSample(float sample) {
+ final int binIndex = mBinOptions.getBinForSample(sample);
+ StatsExpressLog.write(StatsExpressLog.EXPRESS_HISTOGRAM_SAMPLE_REPORTED, mMetricIdHash,
+ /*count*/ 1, binIndex);
+ }
+
+ /**
+ * Logs increment sample count for automatically calculated bin
+ *
+ * @param uid used as a dimension for the count metric
+ * @param sample value
+ */
+ public void logSampleWithUid(int uid, float sample) {
+ final int binIndex = mBinOptions.getBinForSample(sample);
+ StatsExpressLog.write(StatsExpressLog.EXPRESS_UID_HISTOGRAM_SAMPLE_REPORTED,
+ mMetricIdHash, /*count*/ 1, binIndex, uid);
+ }
+
+ /** Used by Histogram to map data sample to corresponding bin */
+ public interface BinOptions {
+ /**
+ * Returns bins count to be used by a histogram
+ *
+ * @return bins count used to initialize Options, including overflow & underflow bins
+ */
+ int getBinsCount();
+
+ /**
+ * Returns bin index for the input sample value
+ * index == 0 stands for underflow
+ * index == getBinsCount() - 1 stands for overflow
+ *
+ * @return zero based index
+ */
+ int getBinForSample(float sample);
+ }
+
+ /** Used by Histogram to map data sample to corresponding bin for uniform bins */
+ public static final class UniformOptions implements BinOptions {
+
+ private final int mBinCount;
+ private final float mMinValue;
+ private final float mExclusiveMaxValue;
+ private final float mBinSize;
+
+ /**
+ * Creates options for uniform (linear) sized bins
+ *
+ * @param binCount amount of histogram bins. 2 bin indexes will be calculated
+ * automatically to represent underflow & overflow bins
+ * @param minValue is included in the first bin, values less than minValue
+ * go to underflow bin
+ * @param exclusiveMaxValue is included in the overflow bucket. For accurate
+ * measure up to kMax, then exclusiveMaxValue
+ * should be set to kMax + 1
+ */
+ public UniformOptions(@IntRange(from = 1) int binCount, float minValue,
+ float exclusiveMaxValue) {
+ if (binCount < 1) {
+ throw new IllegalArgumentException("Bin count should be positive number");
+ }
+
+ if (exclusiveMaxValue <= minValue) {
+ throw new IllegalArgumentException("Bins range invalid (maxValue < minValue)");
+ }
+
+ mMinValue = minValue;
+ mExclusiveMaxValue = exclusiveMaxValue;
+ mBinSize = (mExclusiveMaxValue - minValue) / binCount;
+
+ // Implicitly add 2 for the extra underflow & overflow bins
+ mBinCount = binCount + 2;
+ }
+
+ @Override
+ public int getBinsCount() {
+ return mBinCount;
+ }
+
+ @Override
+ public int getBinForSample(float sample) {
+ if (sample < mMinValue) {
+ // goes to underflow
+ return 0;
+ } else if (sample >= mExclusiveMaxValue) {
+ // goes to overflow
+ return mBinCount - 1;
+ }
+ return (int) ((sample - mMinValue) / mBinSize + 1);
+ }
+ }
+
+ /** Used by Histogram to map data sample to corresponding bin for scaled bins */
+ public static final class ScaledRangeOptions implements BinOptions {
+ // store minimum value per bin
+ final long[] mBins;
+
+ /**
+ * Creates options for scaled range bins
+ *
+ * @param binCount amount of histogram bins. 2 bin indexes will be calculated
+ * automatically to represent underflow & overflow bins
+ * @param minValue is included in the first bin, values less than minValue
+ * go to underflow bin
+ * @param firstBinWidth used to represent first bin width and as a reference to calculate
+ * width for consecutive bins
+ * @param scaleFactor used to calculate width for consecutive bins
+ */
+ public ScaledRangeOptions(@IntRange(from = 1) int binCount, int minValue,
+ @FloatRange(from = 1.f) float firstBinWidth,
+ @FloatRange(from = 1.f) float scaleFactor) {
+ if (binCount < 1) {
+ throw new IllegalArgumentException("Bin count should be positive number");
+ }
+
+ if (firstBinWidth < 1.f) {
+ throw new IllegalArgumentException(
+ "First bin width invalid (should be 1.f at minimum)");
+ }
+
+ if (scaleFactor < 1.f) {
+ throw new IllegalArgumentException(
+ "Scaled factor invalid (should be 1.f at minimum)");
+ }
+
+ // precalculating bins ranges (no need to create a bin for underflow reference value)
+ mBins = initBins(binCount + 1, minValue, firstBinWidth, scaleFactor);
+ }
+
+ @Override
+ public int getBinsCount() {
+ return mBins.length + 1;
+ }
+
+ @Override
+ public int getBinForSample(float sample) {
+ if (sample < mBins[0]) {
+ // goes to underflow
+ return 0;
+ } else if (sample >= mBins[mBins.length - 1]) {
+ // goes to overflow
+ return mBins.length;
+ }
+
+ return lower_bound(mBins, (long) sample) + 1;
+ }
+
+ // To find lower bound using binary search implementation of Arrays utility class
+ private static int lower_bound(long[] array, long sample) {
+ int index = Arrays.binarySearch(array, sample);
+ // If key is not present in the array
+ if (index < 0) {
+ // Index specify the position of the key when inserted in the sorted array
+ // so the element currently present at this position will be the lower bound
+ return Math.abs(index) - 2;
+ }
+ return index;
+ }
+
+ private static long[] initBins(int count, int minValue, float firstBinWidth,
+ float scaleFactor) {
+ long[] bins = new long[count];
+ bins[0] = minValue;
+ double lastWidth = firstBinWidth;
+ for (int i = 1; i < count; i++) {
+ // current bin minValue = previous bin width * scaleFactor
+ double currentBinMinValue = bins[i - 1] + lastWidth;
+ if (currentBinMinValue > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException(
+ "Attempted to create a bucket larger than maxint");
+ }
+
+ bins[i] = (long) currentBinMinValue;
+ lastWidth *= scaleFactor;
+ }
+ return bins;
+ }
+ }
+}
diff --git a/java/com/android/modules/expresslog/OWNERS b/java/com/android/modules/expresslog/OWNERS
new file mode 100644
index 0000000..d3a5812
--- /dev/null
+++ b/java/com/android/modules/expresslog/OWNERS
@@ -0,0 +1,10 @@
+# Bug component: 719316
+# Stats/expresslog
+
+jeffreyhuang@google.com
+muhammadq@google.com
+rslawik@google.com
+sharaienko@google.com
+singhtejinder@google.com
+tsaichristine@google.com
+yaochen@google.com
diff --git a/java/com/android/modules/expresslog/TEST_MAPPING b/java/com/android/modules/expresslog/TEST_MAPPING
new file mode 100644
index 0000000..e658d7a
--- /dev/null
+++ b/java/com/android/modules/expresslog/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "ExpressLogApisTests",
+ "options": [
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ }
+ ]
+}
diff --git a/java/com/android/modules/expresslog/Utils.java b/java/com/android/modules/expresslog/Utils.java
new file mode 100644
index 0000000..fde90fc
--- /dev/null
+++ b/java/com/android/modules/expresslog/Utils.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.modules.expresslog;
+
+final class Utils {
+ static native long hashString(String stringToHash);
+}