Broadscale logging for Settings
Bug: 26687914
Change-Id: Ida75ccf95376538e2ba95d212d333c40fd2dd6e0
diff --git a/src/com/android/settings/InstrumentedFragment.java b/src/com/android/settings/InstrumentedFragment.java
index db14a9cf..b5f99b5 100644
--- a/src/com/android/settings/InstrumentedFragment.java
+++ b/src/com/android/settings/InstrumentedFragment.java
@@ -16,11 +16,11 @@
package com.android.settings;
+import com.android.internal.logging.MetricsLogger;
+
import android.os.Bundle;
import android.support.v14.preference.PreferenceFragment;
-import com.android.internal.logging.MetricsLogger;
-
/**
* Instrumented fragment that logs visibility state.
*/
@@ -44,6 +44,10 @@
public static final int DATA_SAVER_SUMMARY = UNDECLARED + 14;
public static final int DATA_USAGE_UNRESTRICTED_ACCESS = UNDECLARED + 15;
+ // Used for generic logging of Settings Preference Persistence, should not be used
+ // outside SharedPreferencesLogger.
+ public static final int ACTION_GENERIC_PACKAGE = UNDECLARED + 16;
+
/**
* Declare the view of this category.
*
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index ce70f4c..38537fb 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -457,6 +457,21 @@
return true;
}
+ @Override
+ public SharedPreferences getSharedPreferences(String name, int mode) {
+ if (name.equals(getPackageName() + "_preferences")) {
+ String tag = getClass().getName();
+ if (getIntent() != null && getIntent().hasExtra(EXTRA_SHOW_FRAGMENT)) {
+ tag = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);
+ }
+ if (tag.startsWith("com.android.settings.")) {
+ tag = tag.replace("com.android.settings.", "");
+ }
+ return new SharedPreferencesLogger(this, tag);
+ }
+ return super.getSharedPreferences(name, mode);
+ }
+
private static boolean isShortCutIntent(final Intent intent) {
Set<String> categories = intent.getCategories();
return (categories != null) && categories.contains("com.android.settings.SHORTCUT");
diff --git a/src/com/android/settings/SharedPreferencesLogger.java b/src/com/android/settings/SharedPreferencesLogger.java
new file mode 100644
index 0000000..ae2c4e5
--- /dev/null
+++ b/src/com/android/settings/SharedPreferencesLogger.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2016 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.settings;
+
+import com.android.internal.logging.MetricsLogger;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.os.AsyncTask;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.Map;
+import java.util.Set;
+
+public class SharedPreferencesLogger implements SharedPreferences {
+
+ private final String mTag;
+ private final Context mContext;
+
+ public SharedPreferencesLogger(Context context, String tag) {
+ mContext = context;
+ mTag = tag;
+ }
+
+ @Override
+ public Map<String, ?> getAll() {
+ return null;
+ }
+
+ @Override
+ public String getString(String key, @Nullable String defValue) {
+ return defValue;
+ }
+
+ @Override
+ public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
+ return defValues;
+ }
+
+ @Override
+ public int getInt(String key, int defValue) {
+ return defValue;
+ }
+
+ @Override
+ public long getLong(String key, long defValue) {
+ return defValue;
+ }
+
+ @Override
+ public float getFloat(String key, float defValue) {
+ return defValue;
+ }
+
+ @Override
+ public boolean getBoolean(String key, boolean defValue) {
+ return defValue;
+ }
+
+ @Override
+ public boolean contains(String key) {
+ return false;
+ }
+
+ @Override
+ public Editor edit() {
+ return new EditorLogger();
+ }
+
+ @Override
+ public void registerOnSharedPreferenceChangeListener(
+ OnSharedPreferenceChangeListener listener) {
+ }
+
+ @Override
+ public void unregisterOnSharedPreferenceChangeListener(
+ OnSharedPreferenceChangeListener listener) {
+ }
+
+ private void logValue(String key, String value) {
+ MetricsLogger.histogram(mContext, mTag + "/" + key + "|" + value, 1);
+ }
+
+ private void logPackageName(String key, String value) {
+ MetricsLogger.histogram(mContext, mTag + "/" + key, 1);
+ MetricsLogger.action(mContext, InstrumentedFragment.ACTION_GENERIC_PACKAGE,
+ mTag + "/" + key + "|" + value);
+ }
+
+ private void safeLogValue(String key, String value) {
+ new AsyncPackageCheck().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, key, value);
+ }
+
+ private class AsyncPackageCheck extends AsyncTask<String, Void, Void> {
+ @Override
+ protected Void doInBackground(String... params) {
+ String key = params[0];
+ String value = params[1];
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ // Check if this might be a component.
+ ComponentName name = ComponentName.unflattenFromString(value);
+ if (value != null) {
+ value = name.getPackageName();
+ }
+ } catch (Exception e) {
+ }
+ try {
+ pm.getPackageInfo(value, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+ logPackageName(key, value);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Clearly not a package, lets log it.
+ logValue(key, value);
+ }
+ return null;
+ }
+ }
+
+ public class EditorLogger implements Editor {
+ @Override
+ public Editor putString(String key, @Nullable String value) {
+ safeLogValue(key, value);
+ return this;
+ }
+
+ @Override
+ public Editor putStringSet(String key, @Nullable Set<String> values) {
+ safeLogValue(key, TextUtils.join(",", values));
+ return this;
+ }
+
+ @Override
+ public Editor putInt(String key, int value) {
+ logValue(key, String.valueOf(value));
+ return this;
+ }
+
+ @Override
+ public Editor putLong(String key, long value) {
+ logValue(key, String.valueOf(value));
+ return this;
+ }
+
+ @Override
+ public Editor putFloat(String key, float value) {
+ logValue(key, String.valueOf(value));
+ return this;
+ }
+
+ @Override
+ public Editor putBoolean(String key, boolean value) {
+ logValue(key, String.valueOf(value));
+ return this;
+ }
+
+ @Override
+ public Editor remove(String key) {
+ return this;
+ }
+
+ @Override
+ public Editor clear() {
+ return this;
+ }
+
+ @Override
+ public boolean commit() {
+ return true;
+ }
+
+ @Override
+ public void apply() {
+ }
+ }
+}