1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settingslib.development;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.os.SystemProperties;
22 import android.support.annotation.VisibleForTesting;
23 import android.support.v4.content.LocalBroadcastManager;
24 import android.support.v7.preference.ListPreference;
25 import android.support.v7.preference.Preference;
26 import android.support.v7.preference.PreferenceScreen;
27 
28 import com.android.settingslib.R;
29 
30 public abstract class AbstractLogdSizePreferenceController extends
31         DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener {
32     public static final String ACTION_LOGD_SIZE_UPDATED = "com.android.settingslib.development."
33             + "AbstractLogdSizePreferenceController.LOGD_SIZE_UPDATED";
34     public static final String EXTRA_CURRENT_LOGD_VALUE = "CURRENT_LOGD_VALUE";
35 
36     @VisibleForTesting
37     static final String LOW_RAM_CONFIG_PROPERTY_KEY = "ro.config.low_ram";
38     private static final String SELECT_LOGD_SIZE_KEY = "select_logd_size";
39     @VisibleForTesting
40     static final String SELECT_LOGD_SIZE_PROPERTY = "persist.logd.size";
41     static final String SELECT_LOGD_TAG_PROPERTY = "persist.log.tag";
42     // Tricky, isLoggable only checks for first character, assumes silence
43     static final String SELECT_LOGD_TAG_SILENCE = "Settings";
44     @VisibleForTesting
45     static final String SELECT_LOGD_SNET_TAG_PROPERTY = "persist.log.tag.snet_event_log";
46     private static final String SELECT_LOGD_RUNTIME_SNET_TAG_PROPERTY = "log.tag.snet_event_log";
47     private static final String SELECT_LOGD_DEFAULT_SIZE_PROPERTY = "ro.logd.size";
48     @VisibleForTesting
49     static final String SELECT_LOGD_DEFAULT_SIZE_VALUE = "262144";
50     private static final String SELECT_LOGD_SVELTE_DEFAULT_SIZE_VALUE = "65536";
51     // 32768 is merely a menu marker, 64K is our lowest log buffer size we replace it with.
52     @VisibleForTesting
53     static final String SELECT_LOGD_MINIMUM_SIZE_VALUE = "65536";
54     static final String SELECT_LOGD_OFF_SIZE_MARKER_VALUE = "32768";
55     @VisibleForTesting
56     static final String DEFAULT_SNET_TAG = "I";
57 
58     private ListPreference mLogdSize;
59 
AbstractLogdSizePreferenceController(Context context)60     public AbstractLogdSizePreferenceController(Context context) {
61         super(context);
62     }
63 
64     @Override
getPreferenceKey()65     public String getPreferenceKey() {
66         return SELECT_LOGD_SIZE_KEY;
67     }
68 
69     @Override
displayPreference(PreferenceScreen screen)70     public void displayPreference(PreferenceScreen screen) {
71         super.displayPreference(screen);
72         if (isAvailable()) {
73             mLogdSize = (ListPreference) screen.findPreference(SELECT_LOGD_SIZE_KEY);
74         }
75     }
76 
77     @Override
onPreferenceChange(Preference preference, Object newValue)78     public boolean onPreferenceChange(Preference preference, Object newValue) {
79         if (preference == mLogdSize) {
80             writeLogdSizeOption(newValue);
81             return true;
82         } else {
83             return false;
84         }
85     }
86 
enablePreference(boolean enabled)87     public void enablePreference(boolean enabled) {
88         if (isAvailable()) {
89             mLogdSize.setEnabled(enabled);
90         }
91     }
92 
defaultLogdSizeValue()93     private String defaultLogdSizeValue() {
94         String defaultValue = SystemProperties.get(SELECT_LOGD_DEFAULT_SIZE_PROPERTY);
95         if ((defaultValue == null) || (defaultValue.length() == 0)) {
96             if (SystemProperties.get("ro.config.low_ram").equals("true")) {
97                 defaultValue = SELECT_LOGD_SVELTE_DEFAULT_SIZE_VALUE;
98             } else {
99                 defaultValue = SELECT_LOGD_DEFAULT_SIZE_VALUE;
100             }
101         }
102         return defaultValue;
103     }
104 
updateLogdSizeValues()105     public void updateLogdSizeValues() {
106         if (mLogdSize != null) {
107             String currentTag = SystemProperties.get(SELECT_LOGD_TAG_PROPERTY);
108             String currentValue = SystemProperties.get(SELECT_LOGD_SIZE_PROPERTY);
109             if ((currentTag != null) && currentTag.startsWith(SELECT_LOGD_TAG_SILENCE)) {
110                 currentValue = SELECT_LOGD_OFF_SIZE_MARKER_VALUE;
111             }
112             LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(
113                     new Intent(ACTION_LOGD_SIZE_UPDATED)
114                             .putExtra(EXTRA_CURRENT_LOGD_VALUE, currentValue));
115             if ((currentValue == null) || (currentValue.length() == 0)) {
116                 currentValue = defaultLogdSizeValue();
117             }
118             String[] values = mContext.getResources()
119                     .getStringArray(R.array.select_logd_size_values);
120             String[] titles = mContext.getResources()
121                     .getStringArray(R.array.select_logd_size_titles);
122             int index = 2; // punt to second entry if not found
123             if (SystemProperties.get("ro.config.low_ram").equals("true")) {
124                 mLogdSize.setEntries(R.array.select_logd_size_lowram_titles);
125                 titles = mContext.getResources()
126                         .getStringArray(R.array.select_logd_size_lowram_titles);
127                 index = 1;
128             }
129             String[] summaries = mContext.getResources()
130                     .getStringArray(R.array.select_logd_size_summaries);
131             for (int i = 0; i < titles.length; i++) {
132                 if (currentValue.equals(values[i])
133                         || currentValue.equals(titles[i])) {
134                     index = i;
135                     break;
136                 }
137             }
138             mLogdSize.setValue(values[index]);
139             mLogdSize.setSummary(summaries[index]);
140         }
141     }
142 
writeLogdSizeOption(Object newValue)143     public void writeLogdSizeOption(Object newValue) {
144         boolean disable = (newValue != null) &&
145                 (newValue.toString().equals(SELECT_LOGD_OFF_SIZE_MARKER_VALUE));
146         String currentTag = SystemProperties.get(SELECT_LOGD_TAG_PROPERTY);
147         if (currentTag == null) {
148             currentTag = "";
149         }
150         // filter clean and unstack all references to our setting
151         String newTag = currentTag.replaceAll(
152                 ",+" + SELECT_LOGD_TAG_SILENCE, "").replaceFirst(
153                 "^" + SELECT_LOGD_TAG_SILENCE + ",*", "").replaceAll(
154                 ",+", ",").replaceFirst(
155                 ",+$", "");
156         if (disable) {
157             newValue = SELECT_LOGD_MINIMUM_SIZE_VALUE;
158             // Make sure snet_event_log get through first, but do not override
159             String snetValue = SystemProperties.get(SELECT_LOGD_SNET_TAG_PROPERTY);
160             if ((snetValue == null) || (snetValue.length() == 0)) {
161                 snetValue = SystemProperties.get(SELECT_LOGD_RUNTIME_SNET_TAG_PROPERTY);
162                 if ((snetValue == null) || (snetValue.length() == 0)) {
163                     SystemProperties.set(SELECT_LOGD_SNET_TAG_PROPERTY, DEFAULT_SNET_TAG);
164                 }
165             }
166             // Silence all log sources, security logs notwithstanding
167             if (newTag.length() != 0) {
168                 newTag = "," + newTag;
169             }
170             // Stack settings, stack to help preserve original value
171             newTag = SELECT_LOGD_TAG_SILENCE + newTag;
172         }
173         if (!newTag.equals(currentTag)) {
174             SystemProperties.set(SELECT_LOGD_TAG_PROPERTY, newTag);
175         }
176         String defaultValue = defaultLogdSizeValue();
177         final String size = ((newValue != null) && (newValue.toString().length() != 0)) ?
178                 newValue.toString() : defaultValue;
179         SystemProperties.set(SELECT_LOGD_SIZE_PROPERTY, defaultValue.equals(size) ? "" : size);
180         SystemProperties.set("ctl.start", "logd-reinit");
181         SystemPropPoker.getInstance().poke();
182         updateLogdSizeValues();
183     }
184 }
185