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 
23 import androidx.annotation.VisibleForTesting;
24 import androidx.localbroadcastmanager.content.LocalBroadcastManager;
25 import androidx.preference.ListPreference;
26 import androidx.preference.Preference;
27 import androidx.preference.PreferenceScreen;
28 
29 import com.android.settingslib.R;
30 
31 public abstract class AbstractLogdSizePreferenceController extends
32         DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener {
33     public static final String ACTION_LOGD_SIZE_UPDATED = "com.android.settingslib.development."
34             + "AbstractLogdSizePreferenceController.LOGD_SIZE_UPDATED";
35     public static final String EXTRA_CURRENT_LOGD_VALUE = "CURRENT_LOGD_VALUE";
36 
37     @VisibleForTesting
38     static final String LOW_RAM_CONFIG_PROPERTY_KEY = "ro.config.low_ram";
39     private static final String SELECT_LOGD_SIZE_KEY = "select_logd_size";
40     @VisibleForTesting
41     static final String SELECT_LOGD_SIZE_PROPERTY = "persist.logd.size";
42     static final String SELECT_LOGD_TAG_PROPERTY = "persist.log.tag";
43     // Tricky, isLoggable only checks for first character, assumes silence
44     static final String SELECT_LOGD_TAG_SILENCE = "Settings";
45     @VisibleForTesting
46     static final String SELECT_LOGD_SNET_TAG_PROPERTY = "persist.log.tag.snet_event_log";
47     private static final String SELECT_LOGD_RUNTIME_SNET_TAG_PROPERTY = "log.tag.snet_event_log";
48     private static final String SELECT_LOGD_DEFAULT_SIZE_PROPERTY = "ro.logd.size";
49     @VisibleForTesting
50     static final String SELECT_LOGD_DEFAULT_SIZE_VALUE = "262144";
51     private static final String SELECT_LOGD_SVELTE_DEFAULT_SIZE_VALUE = "65536";
52     // 32768 is merely a menu marker, 64K is our lowest log buffer size we replace it with.
53     @VisibleForTesting
54     static final String SELECT_LOGD_MINIMUM_SIZE_VALUE = "65536";
55     static final String SELECT_LOGD_OFF_SIZE_MARKER_VALUE = "32768";
56     @VisibleForTesting
57     static final String DEFAULT_SNET_TAG = "I";
58 
59     private ListPreference mLogdSize;
60 
AbstractLogdSizePreferenceController(Context context)61     public AbstractLogdSizePreferenceController(Context context) {
62         super(context);
63     }
64 
65     @Override
getPreferenceKey()66     public String getPreferenceKey() {
67         return SELECT_LOGD_SIZE_KEY;
68     }
69 
70     @Override
displayPreference(PreferenceScreen screen)71     public void displayPreference(PreferenceScreen screen) {
72         super.displayPreference(screen);
73         if (isAvailable()) {
74             mLogdSize = (ListPreference) screen.findPreference(SELECT_LOGD_SIZE_KEY);
75         }
76     }
77 
78     @Override
onPreferenceChange(Preference preference, Object newValue)79     public boolean onPreferenceChange(Preference preference, Object newValue) {
80         if (preference == mLogdSize) {
81             writeLogdSizeOption(newValue);
82             return true;
83         } else {
84             return false;
85         }
86     }
87 
enablePreference(boolean enabled)88     public void enablePreference(boolean enabled) {
89         if (isAvailable()) {
90             mLogdSize.setEnabled(enabled);
91         }
92     }
93 
defaultLogdSizeValue()94     private String defaultLogdSizeValue() {
95         String defaultValue = SystemProperties.get(SELECT_LOGD_DEFAULT_SIZE_PROPERTY);
96         if ((defaultValue == null) || (defaultValue.length() == 0)) {
97             if (SystemProperties.get("ro.config.low_ram").equals("true")) {
98                 defaultValue = SELECT_LOGD_SVELTE_DEFAULT_SIZE_VALUE;
99             } else {
100                 defaultValue = SELECT_LOGD_DEFAULT_SIZE_VALUE;
101             }
102         }
103         return defaultValue;
104     }
105 
updateLogdSizeValues()106     public void updateLogdSizeValues() {
107         if (mLogdSize != null) {
108             String currentTag = SystemProperties.get(SELECT_LOGD_TAG_PROPERTY);
109             String currentValue = SystemProperties.get(SELECT_LOGD_SIZE_PROPERTY);
110             if ((currentTag != null) && currentTag.startsWith(SELECT_LOGD_TAG_SILENCE)) {
111                 currentValue = SELECT_LOGD_OFF_SIZE_MARKER_VALUE;
112             }
113             LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(
114                     new Intent(ACTION_LOGD_SIZE_UPDATED)
115                             .putExtra(EXTRA_CURRENT_LOGD_VALUE, currentValue));
116             if ((currentValue == null) || (currentValue.length() == 0)) {
117                 currentValue = defaultLogdSizeValue();
118             }
119             String[] values = mContext.getResources()
120                     .getStringArray(R.array.select_logd_size_values);
121             String[] titles = mContext.getResources()
122                     .getStringArray(R.array.select_logd_size_titles);
123             int index = 2; // punt to second entry if not found
124             if (SystemProperties.get("ro.config.low_ram").equals("true")) {
125                 mLogdSize.setEntries(R.array.select_logd_size_lowram_titles);
126                 titles = mContext.getResources()
127                         .getStringArray(R.array.select_logd_size_lowram_titles);
128                 index = 1;
129             }
130             String[] summaries = mContext.getResources()
131                     .getStringArray(R.array.select_logd_size_summaries);
132             for (int i = 0; i < titles.length; i++) {
133                 if (currentValue.equals(values[i])
134                         || currentValue.equals(titles[i])) {
135                     index = i;
136                     break;
137                 }
138             }
139             mLogdSize.setValue(values[index]);
140             mLogdSize.setSummary(summaries[index]);
141         }
142     }
143 
writeLogdSizeOption(Object newValue)144     public void writeLogdSizeOption(Object newValue) {
145         boolean disable = (newValue != null) &&
146                 (newValue.toString().equals(SELECT_LOGD_OFF_SIZE_MARKER_VALUE));
147         String currentTag = SystemProperties.get(SELECT_LOGD_TAG_PROPERTY);
148         if (currentTag == null) {
149             currentTag = "";
150         }
151         // filter clean and unstack all references to our setting
152         String newTag = currentTag.replaceAll(
153                 ",+" + SELECT_LOGD_TAG_SILENCE, "").replaceFirst(
154                 "^" + SELECT_LOGD_TAG_SILENCE + ",*", "").replaceAll(
155                 ",+", ",").replaceFirst(
156                 ",+$", "");
157         if (disable) {
158             newValue = SELECT_LOGD_MINIMUM_SIZE_VALUE;
159             // Make sure snet_event_log get through first, but do not override
160             String snetValue = SystemProperties.get(SELECT_LOGD_SNET_TAG_PROPERTY);
161             if ((snetValue == null) || (snetValue.length() == 0)) {
162                 snetValue = SystemProperties.get(SELECT_LOGD_RUNTIME_SNET_TAG_PROPERTY);
163                 if ((snetValue == null) || (snetValue.length() == 0)) {
164                     SystemProperties.set(SELECT_LOGD_SNET_TAG_PROPERTY, DEFAULT_SNET_TAG);
165                 }
166             }
167             // Silence all log sources, security logs notwithstanding
168             if (newTag.length() != 0) {
169                 newTag = "," + newTag;
170             }
171             // Stack settings, stack to help preserve original value
172             newTag = SELECT_LOGD_TAG_SILENCE + newTag;
173         }
174         if (!newTag.equals(currentTag)) {
175             SystemProperties.set(SELECT_LOGD_TAG_PROPERTY, newTag);
176         }
177         String defaultValue = defaultLogdSizeValue();
178         final String size = ((newValue != null) && (newValue.toString().length() != 0)) ?
179                 newValue.toString() : defaultValue;
180         SystemProperties.set(SELECT_LOGD_SIZE_PROPERTY, defaultValue.equals(size) ? "" : size);
181         SystemProperties.set("ctl.start", "logd-reinit");
182         SystemPropPoker.getInstance().poke();
183         updateLogdSizeValues();
184     }
185 }
186