Merge "Add statslog logging for hidden api usage"
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index e49b65e..650232f 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -253,6 +253,11 @@
private int mHiddenApiAccessLogSampleRate;
/**
+ * Proportion of hidden API accesses that should be logged to statslog; 0 - 0x10000.
+ */
+ private int mHiddenApiAccessStatslogSampleRate;
+
+ /**
* The state of the connection to the primary zygote.
*/
private ZygoteState primaryZygoteState;
@@ -487,6 +492,7 @@
"--start-child-zygote",
"--set-api-blacklist-exemptions",
"--hidden-api-log-sampling-rate",
+ "--hidden-api-statslog-sampling-rate",
"--invoke-with"
};
@@ -776,6 +782,21 @@
}
}
+ /**
+ * Set the precentage of detected hidden API accesses that are logged to the new event log.
+ *
+ * <p>This rate will take affect for all new processes forked from the zygote after this call.
+ *
+ * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging.
+ */
+ public void setHiddenApiAccessStatslogSampleRate(int rate) {
+ synchronized (mLock) {
+ mHiddenApiAccessStatslogSampleRate = rate;
+ maybeSetHiddenApiAccessStatslogSampleRate(primaryZygoteState);
+ maybeSetHiddenApiAccessStatslogSampleRate(secondaryZygoteState);
+ }
+ }
+
@GuardedBy("mLock")
private boolean maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIfEmpty) {
if (state == null || state.isClosed()) {
@@ -830,6 +851,30 @@
}
}
+ private void maybeSetHiddenApiAccessStatslogSampleRate(ZygoteState state) {
+ if (state == null || state.isClosed()) {
+ return;
+ }
+ if (mHiddenApiAccessStatslogSampleRate == -1) {
+ return;
+ }
+ try {
+ state.mZygoteOutputWriter.write(Integer.toString(1));
+ state.mZygoteOutputWriter.newLine();
+ state.mZygoteOutputWriter.write("--hidden-api-statslog-sampling-rate="
+ + Integer.toString(mHiddenApiAccessStatslogSampleRate));
+ state.mZygoteOutputWriter.newLine();
+ state.mZygoteOutputWriter.flush();
+ int status = state.mZygoteInputStream.readInt();
+ if (status != 0) {
+ Slog.e(LOG_TAG, "Failed to set hidden API statslog sampling rate; status "
+ + status);
+ }
+ } catch (IOException ioe) {
+ Slog.e(LOG_TAG, "Failed to set hidden API statslog sampling rate", ioe);
+ }
+ }
+
/**
* Creates a ZygoteState for the primary zygote if it doesn't exist or has been disconnected.
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0d7e00f..d395a9f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -13376,8 +13376,8 @@
"hidden_api_blacklist_exemptions";
/**
- * Sampling rate for hidden API access event logs, as an integer in the range 0 to 0x10000
- * inclusive.
+ * Sampling rate for hidden API access event logs with libmetricslogger, as an integer in
+ * the range 0 to 0x10000 inclusive.
*
* @hide
*/
@@ -13385,6 +13385,15 @@
"hidden_api_access_log_sampling_rate";
/**
+ * Sampling rate for hidden API access event logging with statslog, as an integer in the
+ * range 0 to 0x10000 inclusive.
+ *
+ * @hide
+ */
+ public static final String HIDDEN_API_ACCESS_STATSLOG_SAMPLING_RATE =
+ "hidden_api_access_statslog_sampling_rate";
+
+ /**
* Hidden API enforcement policy for apps.
*
* Values correspond to @{@link
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 58b48d8..0ccaec0 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -645,6 +645,9 @@
} else if (args.mHiddenApiAccessLogSampleRate != -1) {
throw new IllegalArgumentException(
BLASTULA_ERROR_PREFIX + "--hidden-api-log-sampling-rate=");
+ } else if (args.mHiddenApiAccessStatslogSampleRate != -1) {
+ throw new IllegalArgumentException(
+ BLASTULA_ERROR_PREFIX + "--hidden-api-statslog-sampling-rate=");
} else if (args.mInvokeWith != null) {
throw new IllegalArgumentException(BLASTULA_ERROR_PREFIX + "--invoke-with");
} else if (args.mPermittedCapabilities != 0 || args.mEffectiveCapabilities != 0) {
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index 9cb5820..3beee78 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -205,6 +205,12 @@
int mHiddenApiAccessLogSampleRate = -1;
/**
+ * Sampling rate for logging hidden API accesses to statslog. This is sent to the
+ * pre-forked zygote at boot time, or when it changes, via --hidden-api-statslog-sampling-rate.
+ */
+ int mHiddenApiAccessStatslogSampleRate = -1;
+
+ /**
* Constructs instance and parses args
*
* @param args zygote command-line args
@@ -391,6 +397,15 @@
"Invalid log sampling rate: " + rateStr, nfe);
}
expectRuntimeArgs = false;
+ } else if (arg.startsWith("--hidden-api-statslog-sampling-rate=")) {
+ String rateStr = arg.substring(arg.indexOf('=') + 1);
+ try {
+ mHiddenApiAccessStatslogSampleRate = Integer.parseInt(rateStr);
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException(
+ "Invalid statslog sampling rate: " + rateStr, nfe);
+ }
+ expectRuntimeArgs = false;
} else if (arg.startsWith("--package-name=")) {
if (mPackageName != null) {
throw new IllegalArgumentException("Duplicate arg specified");
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index c7ba22d..bcdce31 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -37,6 +37,7 @@
import android.system.Os;
import android.system.StructPollfd;
import android.util.Log;
+import android.util.StatsLog;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -192,9 +193,11 @@
return handleApiBlacklistExemptions(zygoteServer, parsedArgs.mApiBlacklistExemptions);
}
- if (parsedArgs.mHiddenApiAccessLogSampleRate != -1) {
+ if (parsedArgs.mHiddenApiAccessLogSampleRate != -1
+ || parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) {
return handleHiddenApiAccessLogSampleRate(zygoteServer,
- parsedArgs.mHiddenApiAccessLogSampleRate);
+ parsedArgs.mHiddenApiAccessLogSampleRate,
+ parsedArgs.mHiddenApiAccessStatslogSampleRate);
}
if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 0) {
@@ -396,9 +399,11 @@
private final MetricsLogger mMetricsLogger = new MetricsLogger();
private static HiddenApiUsageLogger sInstance = new HiddenApiUsageLogger();
private int mHiddenApiAccessLogSampleRate = 0;
+ private int mHiddenApiAccessStatslogSampleRate = 0;
- public static void setHiddenApiAccessLogSampleRate(int sampleRate) {
+ public static void setHiddenApiAccessLogSampleRates(int sampleRate, int newSampleRate) {
sInstance.mHiddenApiAccessLogSampleRate = sampleRate;
+ sInstance.mHiddenApiAccessStatslogSampleRate = newSampleRate;
}
public static HiddenApiUsageLogger getInstance() {
@@ -410,6 +415,9 @@
if (sampledValue < mHiddenApiAccessLogSampleRate) {
logUsage(packageName, signature, accessMethod, accessDenied);
}
+ if (sampledValue < mHiddenApiAccessStatslogSampleRate) {
+ newLogUsage(signature, accessMethod, accessDenied);
+ }
}
private void logUsage(String packageName, String signature, int accessMethod,
@@ -439,6 +447,27 @@
}
mMetricsLogger.write(logMaker);
}
+
+ private void newLogUsage(String signature, int accessMethod, boolean accessDenied) {
+ int accessMethodProto = StatsLog.HIDDEN_API_USED__ACCESS_METHOD__NONE;
+ switch(accessMethod) {
+ case HiddenApiUsageLogger.ACCESS_METHOD_NONE:
+ accessMethodProto = StatsLog.HIDDEN_API_USED__ACCESS_METHOD__NONE;
+ break;
+ case HiddenApiUsageLogger.ACCESS_METHOD_REFLECTION:
+ accessMethodProto = StatsLog.HIDDEN_API_USED__ACCESS_METHOD__REFLECTION;
+ break;
+ case HiddenApiUsageLogger.ACCESS_METHOD_JNI:
+ accessMethodProto = StatsLog.HIDDEN_API_USED__ACCESS_METHOD__JNI;
+ break;
+ case HiddenApiUsageLogger.ACCESS_METHOD_LINKING:
+ accessMethodProto = StatsLog.HIDDEN_API_USED__ACCESS_METHOD__LINKING;
+ break;
+ }
+ int uid = Process.myUid();
+ StatsLog.write(StatsLog.HIDDEN_API_USED, uid, signature,
+ accessMethodProto, accessDenied);
+ }
}
/**
@@ -450,15 +479,18 @@
* a Runnable object that must be returned to ZygoteServer.runSelectLoop to be invoked.
*
* @param zygoteServer The server object that received the request
- * @param samplingRate The new sample rate
+ * @param samplingRate The new sample rate for regular logging
+ * @param statsdSamplingRate The new sample rate for statslog logging
* @return A Runnable object representing a new app in any blastulas spawned from here; the
* zygote process will always receive a null value from this function.
*/
private Runnable handleHiddenApiAccessLogSampleRate(ZygoteServer zygoteServer,
- int samplingRate) {
+ int samplingRate, int statsdSamplingRate) {
return stateChangeWithBlastulaPoolReset(zygoteServer, () -> {
- ZygoteInit.setHiddenApiAccessLogSampleRate(samplingRate);
- HiddenApiUsageLogger.setHiddenApiAccessLogSampleRate(samplingRate);
+ int maxSamplingRate = Math.max(samplingRate, statsdSamplingRate);
+ ZygoteInit.setHiddenApiAccessLogSampleRate(maxSamplingRate);
+ HiddenApiUsageLogger.setHiddenApiAccessLogSampleRates(samplingRate,
+ statsdSamplingRate);
ZygoteInit.setHiddenApiUsageLogger(HiddenApiUsageLogger.getInstance());
});
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 23cd963..69632c1 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -287,6 +287,7 @@
Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
Settings.Global.HIDDEN_API_ACCESS_LOG_SAMPLING_RATE,
+ Settings.Global.HIDDEN_API_ACCESS_STATSLOG_SAMPLING_RATE,
Settings.Global.HIDDEN_API_POLICY,
Settings.Global.HIDE_ERROR_DIALOGS,
Settings.Global.HTTP_PROXY,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fe85d23..ccb9d82 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2129,6 +2129,7 @@
private String mExemptionsStr;
private List<String> mExemptions = Collections.emptyList();
private int mLogSampleRate = -1;
+ private int mStatslogSampleRate = -1;
@HiddenApiEnforcementPolicy private int mPolicy = HIDDEN_API_ENFORCEMENT_DEFAULT;
public HiddenApiSettings(Handler handler, Context context) {
@@ -2146,6 +2147,11 @@
false,
this);
mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(
+ Settings.Global.HIDDEN_API_ACCESS_STATSLOG_SAMPLING_RATE),
+ false,
+ this);
+ mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.HIDDEN_API_POLICY),
false,
this);
@@ -2181,6 +2187,15 @@
mLogSampleRate = logSampleRate;
ZYGOTE_PROCESS.setHiddenApiAccessLogSampleRate(mLogSampleRate);
}
+ int statslogSampleRate = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.HIDDEN_API_ACCESS_STATSLOG_SAMPLING_RATE, 0);
+ if (statslogSampleRate < 0 || statslogSampleRate > 0x10000) {
+ statslogSampleRate = -1;
+ }
+ if (statslogSampleRate != -1 && statslogSampleRate != mStatslogSampleRate) {
+ mStatslogSampleRate = statslogSampleRate;
+ ZYGOTE_PROCESS.setHiddenApiAccessStatslogSampleRate(mStatslogSampleRate);
+ }
mPolicy = getValidEnforcementPolicy(Settings.Global.HIDDEN_API_POLICY);
}