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 17package com.android.settings.fuelgauge.anomaly; 18 19import android.content.Context; 20import android.content.pm.PackageManager; 21import android.os.BatteryStats; 22import android.os.Bundle; 23import android.os.UserManager; 24import android.support.annotation.VisibleForTesting; 25import android.util.Log; 26 27import com.android.internal.os.BatteryStatsHelper; 28import com.android.internal.util.ArrayUtils; 29import com.android.settings.utils.AsyncLoader; 30 31import java.io.FileDescriptor; 32import java.io.PrintWriter; 33import java.util.ArrayList; 34import java.util.List; 35 36/** 37 * Loader to compute which apps are anomaly and return a anomaly list. It will return 38 * an empty list if there is no anomaly. 39 */ 40public class AnomalyLoader extends AsyncLoader<List<Anomaly>> { 41 private static final String TAG = "AnomalyLoader"; 42 43 private static final boolean USE_FAKE_DATA = false; 44 private BatteryStatsHelper mBatteryStatsHelper; 45 private String mPackageName; 46 private UserManager mUserManager; 47 @VisibleForTesting 48 AnomalyUtils mAnomalyUtils; 49 @VisibleForTesting 50 AnomalyDetectionPolicy mPolicy; 51 52 /** 53 * Create {@link AnomalyLoader} that runs anomaly check for all apps. 54 */ 55 public AnomalyLoader(Context context, BatteryStatsHelper batteryStatsHelper) { 56 this(context, batteryStatsHelper, null, new AnomalyDetectionPolicy(context)); 57 58 } 59 60 /** 61 * Create {@link AnomalyLoader} with {@code packageName}, so this loader will only 62 * detect anomalies related to {@code packageName}, or check all apps if {@code packageName} 63 * is {@code null}. 64 * 65 * This constructor will create {@link BatteryStatsHelper} in background thread. 66 * 67 * @param packageName if set, only finds anomalies for this package. If {@code null}, 68 * detects all anomalies of this type. 69 */ 70 public AnomalyLoader(Context context, String packageName) { 71 this(context, null, packageName, new AnomalyDetectionPolicy(context)); 72 } 73 74 @VisibleForTesting 75 AnomalyLoader(Context context, BatteryStatsHelper batteryStatsHelper, 76 String packageName, AnomalyDetectionPolicy policy) { 77 super(context); 78 mBatteryStatsHelper = batteryStatsHelper; 79 mPackageName = packageName; 80 mAnomalyUtils = AnomalyUtils.getInstance(context); 81 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 82 mPolicy = policy; 83 } 84 85 @Override 86 protected void onDiscardResult(List<Anomaly> result) { 87 } 88 89 @Override 90 public List<Anomaly> loadInBackground() { 91 if (USE_FAKE_DATA) { 92 return generateFakeData(); 93 } 94 if (mBatteryStatsHelper == null) { 95 mBatteryStatsHelper = new BatteryStatsHelper(getContext()); 96 mBatteryStatsHelper.create((Bundle) null); 97 mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, 98 mUserManager.getUserProfiles()); 99 } 100 101 return mAnomalyUtils.detectAnomalies(mBatteryStatsHelper, mPolicy, mPackageName); 102 } 103 104 @VisibleForTesting 105 List<Anomaly> generateFakeData() { 106 final List<Anomaly> anomalies = new ArrayList<>(); 107 final Context context = getContext(); 108 final String packageName = "com.android.settings"; 109 final CharSequence displayName = "Settings"; 110 try { 111 final int uid = context.getPackageManager().getPackageUid(packageName, 0); 112 113 anomalies.add(new Anomaly.Builder() 114 .setUid(uid) 115 .setType(Anomaly.AnomalyType.WAKE_LOCK) 116 .setPackageName(packageName) 117 .setDisplayName(displayName) 118 .build()); 119 anomalies.add(new Anomaly.Builder() 120 .setUid(uid) 121 .setType(Anomaly.AnomalyType.WAKEUP_ALARM) 122 .setPackageName(packageName) 123 .setDisplayName(displayName) 124 .build()); 125 anomalies.add(new Anomaly.Builder() 126 .setUid(uid) 127 .setType(Anomaly.AnomalyType.BLUETOOTH_SCAN) 128 .setPackageName(packageName) 129 .setDisplayName(displayName) 130 .build()); 131 } catch (PackageManager.NameNotFoundException e) { 132 Log.e(TAG, "Cannot find package by name: " + packageName, e); 133 } 134 return anomalies; 135 } 136 137} 138