1 /*
2  * Copyright (C) 2020 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.settings.development;
18 
19 import android.annotation.Nullable;
20 import android.content.Context;
21 import android.hardware.dumpstate.V1_0.IDumpstateDevice;
22 import android.os.RemoteException;
23 import android.util.Log;
24 
25 import androidx.annotation.VisibleForTesting;
26 import androidx.preference.Preference;
27 import androidx.preference.SwitchPreference;
28 
29 import com.android.settings.core.PreferenceControllerMixin;
30 import com.android.settingslib.development.DeveloperOptionsPreferenceController;
31 
32 import java.util.NoSuchElementException;
33 
34 public class EnableVerboseVendorLoggingPreferenceController
35         extends DeveloperOptionsPreferenceController
36         implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
37 
38     private static final String TAG = "EnableVerboseVendorLoggingPreferenceController";
39     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
40 
41     private static final String ENABLE_VERBOSE_VENDOR_LOGGING_KEY = "enable_verbose_vendor_logging";
42     private static final int DUMPSTATE_HAL_VERSION_UNKNOWN = -1;
43     private static final int DUMPSTATE_HAL_VERSION_1_0 = 0;
44     private static final int DUMPSTATE_HAL_VERSION_1_1 = 1;
45 
46     private int mDumpstateHalVersion;
47 
EnableVerboseVendorLoggingPreferenceController(Context context)48     public EnableVerboseVendorLoggingPreferenceController(Context context) {
49         super(context);
50         mDumpstateHalVersion = DUMPSTATE_HAL_VERSION_UNKNOWN;
51     }
52 
53     @Override
getPreferenceKey()54     public String getPreferenceKey() {
55         return ENABLE_VERBOSE_VENDOR_LOGGING_KEY;
56     }
57 
58     @Override
isAvailable()59     public boolean isAvailable() {
60         // Only show preference when IDumpstateDevice v1.1 is avalaible
61         // This is temperary strategy that may change later.
62         return isIDumpstateDeviceV1_1ServiceAvailable();
63     }
64 
65     @Override
onPreferenceChange(Preference preference, Object newValue)66     public boolean onPreferenceChange(Preference preference, Object newValue) {
67         final boolean isEnabled = (Boolean) newValue;
68         setVerboseLoggingEnabled(isEnabled);
69         return true;
70     }
71 
72     @Override
updateState(Preference preference)73     public void updateState(Preference preference) {
74         final boolean enabled = getVerboseLoggingEnabled();
75         ((SwitchPreference) mPreference).setChecked(enabled);
76     }
77 
78     @Override
onDeveloperOptionsSwitchDisabled()79     protected void onDeveloperOptionsSwitchDisabled() {
80         super.onDeveloperOptionsSwitchDisabled();
81         setVerboseLoggingEnabled(false);
82         ((SwitchPreference) mPreference).setChecked(false);
83     }
84 
85     @VisibleForTesting
isIDumpstateDeviceV1_1ServiceAvailable()86     boolean isIDumpstateDeviceV1_1ServiceAvailable() {
87         IDumpstateDevice service = getDumpstateDeviceService();
88         if (service == null) {
89             if (DBG) Log.d(TAG, "IDumpstateDevice service is not available.");
90         }
91         return service != null && mDumpstateHalVersion >= DUMPSTATE_HAL_VERSION_1_1;
92     }
93 
94     @VisibleForTesting
setVerboseLoggingEnabled(boolean enable)95     void setVerboseLoggingEnabled(boolean enable) {
96         IDumpstateDevice service = getDumpstateDeviceService();
97 
98         if (service == null || mDumpstateHalVersion < DUMPSTATE_HAL_VERSION_1_1) {
99             if (DBG) Log.d(TAG, "setVerboseLoggingEnabled not supported.");
100             return;
101         }
102 
103         try {
104             android.hardware.dumpstate.V1_1.IDumpstateDevice service11 =
105                     (android.hardware.dumpstate.V1_1.IDumpstateDevice) service;
106             if (service11 != null) {
107                 service11.setVerboseLoggingEnabled(enable);
108             }
109         } catch (RemoteException | RuntimeException e) {
110             if (DBG) Log.e(TAG, "setVerboseLoggingEnabled fail: " + e);
111         }
112     }
113 
114     @VisibleForTesting
getVerboseLoggingEnabled()115     boolean getVerboseLoggingEnabled() {
116         IDumpstateDevice service = getDumpstateDeviceService();
117 
118         if (service == null || mDumpstateHalVersion < DUMPSTATE_HAL_VERSION_1_1) {
119             if (DBG) Log.d(TAG, "getVerboseLoggingEnabled not supported.");
120             return false;
121         }
122 
123         try {
124             android.hardware.dumpstate.V1_1.IDumpstateDevice service11 =
125                     (android.hardware.dumpstate.V1_1.IDumpstateDevice) service;
126             if (service11 != null) {
127                 return service11.getVerboseLoggingEnabled();
128             }
129         } catch (RemoteException | RuntimeException e) {
130             if (DBG) Log.e(TAG, "getVerboseLoggingEnabled fail: " + e);
131         }
132         return false;
133     }
134 
135     /** Return a {@IDumpstateDevice} instance or null if service is not available. */
136     @VisibleForTesting
getDumpstateDeviceService()137     @Nullable IDumpstateDevice getDumpstateDeviceService() {
138         IDumpstateDevice service = null;
139         try {
140             service = android.hardware.dumpstate.V1_1.IDumpstateDevice
141                     .getService(true /* retry */);
142             mDumpstateHalVersion = DUMPSTATE_HAL_VERSION_1_1;
143         } catch (NoSuchElementException | RemoteException e) {
144         }
145 
146         if (service == null) {
147             try {
148                 service = android.hardware.dumpstate.V1_0.IDumpstateDevice
149                         .getService(true /* retry */);
150                 mDumpstateHalVersion = DUMPSTATE_HAL_VERSION_1_0;
151             } catch (NoSuchElementException | RemoteException e) {
152             }
153         }
154 
155         if (service == null) {
156             mDumpstateHalVersion = DUMPSTATE_HAL_VERSION_UNKNOWN;
157         }
158         return service;
159     }
160 }
161