| /* | |
| * 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 static android.content.pm.PackageManager.FEATURE_ETHERNET; | |
| import static android.content.pm.PackageManager.FEATURE_WIFI; | |
| import android.app.Service; | |
| import android.content.Context; | |
| import android.content.Intent; | |
| import android.content.SharedPreferences; | |
| import android.content.pm.PackageManager; | |
| import android.content.pm.ResolveInfo; | |
| import android.net.NetworkTemplate; | |
| import android.net.Uri; | |
| import android.os.IBinder; | |
| import android.os.storage.StorageManager; | |
| import android.os.storage.VolumeInfo; | |
| import android.telephony.SubscriptionInfo; | |
| import android.telephony.SubscriptionManager; | |
| import android.telephony.TelephonyManager; | |
| import android.util.IndentingPrintWriter; | |
| import android.util.Log; | |
| import androidx.annotation.VisibleForTesting; | |
| import com.android.settings.applications.ProcStatsData; | |
| import com.android.settings.datausage.lib.DataUsageLib; | |
| import com.android.settings.network.MobileNetworkRepository; | |
| import com.android.settingslib.net.DataUsageController; | |
| import org.json.JSONArray; | |
| import org.json.JSONException; | |
| import org.json.JSONObject; | |
| import java.io.File; | |
| import java.io.FileDescriptor; | |
| import java.io.PrintWriter; | |
| public class SettingsDumpService extends Service { | |
| public static final String EXTRA_KEY_SHOW_NETWORK_DUMP = "show_network_dump"; | |
| private static final String TAG = "SettingsDumpService"; | |
| @VisibleForTesting | |
| static final String KEY_SERVICE = "service"; | |
| @VisibleForTesting | |
| static final String KEY_STORAGE = "storage"; | |
| @VisibleForTesting | |
| static final String KEY_DATAUSAGE = "datausage"; | |
| @VisibleForTesting | |
| static final String KEY_MEMORY = "memory"; | |
| @VisibleForTesting | |
| static final String KEY_DEFAULT_BROWSER_APP = "default_browser_app"; | |
| @VisibleForTesting | |
| static final String KEY_ANOMALY_DETECTION = "anomaly_detection"; | |
| @VisibleForTesting | |
| static final Intent BROWSER_INTENT = | |
| new Intent("android.intent.action.VIEW", Uri.parse("http://")); | |
| private boolean mShouldShowNetworkDump = false; | |
| @Override | |
| public int onStartCommand(Intent intent, int flags, int startId) { | |
| if (intent != null) { | |
| mShouldShowNetworkDump = intent.getBooleanExtra(EXTRA_KEY_SHOW_NETWORK_DUMP, false); | |
| } | |
| return Service.START_REDELIVER_INTENT; | |
| } | |
| @Override | |
| public IBinder onBind(Intent intent) { | |
| return null; | |
| } | |
| @Override | |
| protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { | |
| IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); | |
| if (!mShouldShowNetworkDump) { | |
| JSONObject dump = new JSONObject(); | |
| pw.println(TAG + ": "); | |
| pw.increaseIndent(); | |
| try { | |
| dump.put(KEY_SERVICE, "Settings State"); | |
| dump.put(KEY_STORAGE, dumpStorage()); | |
| dump.put(KEY_DATAUSAGE, dumpDataUsage()); | |
| dump.put(KEY_MEMORY, dumpMemory()); | |
| dump.put(KEY_DEFAULT_BROWSER_APP, dumpDefaultBrowser()); | |
| } catch (Exception e) { | |
| Log.w(TAG, "exception in dump: ", e); | |
| } | |
| pw.println(dump); | |
| pw.flush(); | |
| pw.decreaseIndent(); | |
| } else { | |
| dumpMobileNetworkSettings(pw); | |
| } | |
| } | |
| private JSONObject dumpMemory() throws JSONException { | |
| JSONObject obj = new JSONObject(); | |
| ProcStatsData statsManager = new ProcStatsData(this, false); | |
| statsManager.refreshStats(true); | |
| ProcStatsData.MemInfo memInfo = statsManager.getMemInfo(); | |
| obj.put("used", String.valueOf(memInfo.realUsedRam)); | |
| obj.put("free", String.valueOf(memInfo.realFreeRam)); | |
| obj.put("total", String.valueOf(memInfo.realTotalRam)); | |
| obj.put("state", statsManager.getMemState()); | |
| return obj; | |
| } | |
| private JSONObject dumpDataUsage() throws JSONException { | |
| JSONObject obj = new JSONObject(); | |
| DataUsageController controller = new DataUsageController(this); | |
| SubscriptionManager manager = this.getSystemService(SubscriptionManager.class); | |
| TelephonyManager telephonyManager = this.getSystemService(TelephonyManager.class); | |
| final PackageManager packageManager = this.getPackageManager(); | |
| if (telephonyManager.isDataCapable()) { | |
| JSONArray array = new JSONArray(); | |
| for (SubscriptionInfo info : manager.getAvailableSubscriptionInfoList()) { | |
| NetworkTemplate template = DataUsageLib.getMobileTemplateForSubId( | |
| telephonyManager, info.getSubscriptionId()); | |
| final JSONObject usage = dumpDataUsage(template, controller); | |
| usage.put("subId", info.getSubscriptionId()); | |
| array.put(usage); | |
| } | |
| obj.put("cell", array); | |
| } | |
| if (packageManager.hasSystemFeature(FEATURE_WIFI)) { | |
| obj.put("wifi", dumpDataUsage( | |
| new NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build(), controller)); | |
| } | |
| if (packageManager.hasSystemFeature(FEATURE_ETHERNET)) { | |
| obj.put("ethernet", dumpDataUsage(new NetworkTemplate.Builder( | |
| NetworkTemplate.MATCH_ETHERNET).build(), controller)); | |
| } | |
| return obj; | |
| } | |
| private JSONObject dumpDataUsage(NetworkTemplate template, DataUsageController controller) | |
| throws JSONException { | |
| JSONObject obj = new JSONObject(); | |
| DataUsageController.DataUsageInfo usage = controller.getDataUsageInfo(template); | |
| obj.put("carrier", usage.carrier); | |
| obj.put("start", usage.startDate); | |
| obj.put("usage", usage.usageLevel); | |
| obj.put("warning", usage.warningLevel); | |
| obj.put("limit", usage.limitLevel); | |
| return obj; | |
| } | |
| private JSONObject dumpStorage() throws JSONException { | |
| JSONObject obj = new JSONObject(); | |
| StorageManager manager = getSystemService(StorageManager.class); | |
| for (VolumeInfo volume : manager.getVolumes()) { | |
| JSONObject volObj = new JSONObject(); | |
| if (volume.isMountedReadable()) { | |
| File path = volume.getPath(); | |
| volObj.put("used", String.valueOf(path.getTotalSpace() - path.getFreeSpace())); | |
| volObj.put("total", String.valueOf(path.getTotalSpace())); | |
| } | |
| volObj.put("path", volume.getInternalPath()); | |
| volObj.put("state", volume.getState()); | |
| volObj.put("stateDesc", volume.getStateDescription()); | |
| volObj.put("description", volume.getDescription()); | |
| obj.put(volume.getId(), volObj); | |
| } | |
| return obj; | |
| } | |
| @VisibleForTesting | |
| String dumpDefaultBrowser() { | |
| final ResolveInfo resolveInfo = getPackageManager().resolveActivity( | |
| BROWSER_INTENT, PackageManager.MATCH_DEFAULT_ONLY); | |
| if (resolveInfo == null || resolveInfo.activityInfo.packageName.equals("android")) { | |
| return null; | |
| } else { | |
| return resolveInfo.activityInfo.packageName; | |
| } | |
| } | |
| private void dumpMobileNetworkSettings(IndentingPrintWriter writer) { | |
| MobileNetworkRepository.getInstance(this).dump(writer); | |
| } | |
| } |