| /* |
| * Copyright (C) 2020 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.server.stats; |
| |
| import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED; |
| import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; |
| import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; |
| import static android.os.Debug.getIonHeapsSizeKb; |
| import static android.os.Process.THREAD_PRIORITY_BACKGROUND; |
| import static android.os.Process.getUidForPid; |
| import static android.os.storage.VolumeInfo.TYPE_PRIVATE; |
| import static android.os.storage.VolumeInfo.TYPE_PUBLIC; |
| |
| import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; |
| import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs; |
| import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs; |
| import static com.android.server.stats.ProcfsMemoryUtil.forEachPid; |
| import static com.android.server.stats.ProcfsMemoryUtil.readCmdlineFromProcfs; |
| import static com.android.server.stats.ProcfsMemoryUtil.readMemorySnapshotFromProcfs; |
| |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.app.ActivityManagerInternal; |
| import android.app.AlarmManager; |
| import android.app.AlarmManager.OnAlarmListener; |
| import android.app.AppOpsManager; |
| import android.app.AppOpsManager.HistoricalOps; |
| import android.app.AppOpsManager.HistoricalOpsRequest; |
| import android.app.AppOpsManager.HistoricalPackageOps; |
| import android.app.AppOpsManager.HistoricalUidOps; |
| import android.app.INotificationManager; |
| import android.app.ProcessMemoryState; |
| import android.app.StatsManager; |
| import android.app.StatsManager.PullAtomMetadata; |
| import android.bluetooth.BluetoothActivityEnergyInfo; |
| import android.bluetooth.BluetoothAdapter; |
| import android.bluetooth.UidTraffic; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.PackageInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.PermissionInfo; |
| import android.content.pm.UserInfo; |
| import android.hardware.biometrics.BiometricsProtoEnums; |
| import android.hardware.face.FaceManager; |
| import android.hardware.fingerprint.FingerprintManager; |
| import android.net.ConnectivityManager; |
| import android.net.INetworkStatsService; |
| import android.net.Network; |
| import android.net.NetworkRequest; |
| import android.net.NetworkStats; |
| import android.net.wifi.WifiManager; |
| import android.os.BatteryStats; |
| import android.os.BatteryStatsInternal; |
| import android.os.Binder; |
| import android.os.Build; |
| import android.os.Bundle; |
| import android.os.CoolingDevice; |
| import android.os.Environment; |
| import android.os.FileUtils; |
| import android.os.Handler; |
| import android.os.HandlerThread; |
| import android.os.IBinder; |
| import android.os.IPullAtomCallback; |
| import android.os.IStatsCompanionService; |
| import android.os.IStatsd; |
| import android.os.IStoraged; |
| import android.os.IThermalEventListener; |
| import android.os.IThermalService; |
| import android.os.Looper; |
| import android.os.ParcelFileDescriptor; |
| import android.os.Parcelable; |
| import android.os.RemoteException; |
| import android.os.ServiceManager; |
| import android.os.StatFs; |
| import android.os.StatsLogEventWrapper; |
| import android.os.SynchronousResultReceiver; |
| import android.os.SystemClock; |
| import android.os.SystemProperties; |
| import android.os.Temperature; |
| import android.os.UserHandle; |
| import android.os.UserManager; |
| import android.os.connectivity.WifiActivityEnergyInfo; |
| import android.os.storage.DiskInfo; |
| import android.os.storage.StorageManager; |
| import android.os.storage.VolumeInfo; |
| import android.provider.Settings; |
| import android.stats.storage.StorageEnums; |
| import android.telephony.ModemActivityInfo; |
| import android.telephony.TelephonyManager; |
| import android.util.ArrayMap; |
| import android.util.ArraySet; |
| import android.util.Log; |
| import android.util.Slog; |
| import android.util.StatsEvent; |
| import android.util.StatsLog; |
| import android.util.proto.ProtoOutputStream; |
| |
| import com.android.internal.annotations.GuardedBy; |
| import com.android.internal.app.procstats.IProcessStats; |
| import com.android.internal.app.procstats.ProcessStats; |
| import com.android.internal.os.BackgroundThread; |
| import com.android.internal.os.BatterySipper; |
| import com.android.internal.os.BatteryStatsHelper; |
| import com.android.internal.os.BinderCallsStats.ExportedCallStat; |
| import com.android.internal.os.KernelCpuSpeedReader; |
| import com.android.internal.os.KernelCpuThreadReader; |
| import com.android.internal.os.KernelCpuThreadReaderDiff; |
| import com.android.internal.os.KernelCpuThreadReaderSettingsObserver; |
| import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader; |
| import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader; |
| import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader; |
| import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader; |
| import com.android.internal.os.KernelWakelockReader; |
| import com.android.internal.os.KernelWakelockStats; |
| import com.android.internal.os.LooperStats; |
| import com.android.internal.os.PowerProfile; |
| import com.android.internal.os.ProcessCpuTracker; |
| import com.android.internal.os.StoragedUidIoStatsReader; |
| import com.android.internal.util.DumpUtils; |
| import com.android.server.BinderCallsStatsService; |
| import com.android.server.LocalServices; |
| import com.android.server.SystemService; |
| import com.android.server.SystemServiceManager; |
| import com.android.server.am.MemoryStatUtil.MemoryStat; |
| import com.android.server.notification.NotificationManagerService; |
| import com.android.server.role.RoleManagerInternal; |
| import com.android.server.stats.IonMemoryUtil.IonAllocations; |
| import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot; |
| import com.android.server.storage.DiskStatsFileLogger; |
| import com.android.server.storage.DiskStatsLoggingService; |
| |
| import com.google.android.collect.Sets; |
| |
| import libcore.io.IoUtils; |
| |
| import org.json.JSONArray; |
| import org.json.JSONException; |
| import org.json.JSONObject; |
| |
| import java.io.File; |
| import java.io.FileDescriptor; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.PrintWriter; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Objects; |
| import java.util.Set; |
| import java.util.UUID; |
| import java.util.concurrent.CompletableFuture; |
| import java.util.concurrent.Executor; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.ThreadLocalRandom; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.TimeoutException; |
| |
| /** |
| * SystemService containing PullAtomCallbacks that are registered with statsd. |
| * |
| * @hide |
| */ |
| public class StatsPullAtomService extends SystemService { |
| private static final String TAG = "StatsPullAtomService"; |
| private static final boolean DEBUG = true; |
| |
| private static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity"; |
| /** |
| * How long to wait on an individual subsystem to return its stats. |
| */ |
| private static final long EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS = 2000; |
| |
| private final Object mNetworkStatsLock = new Object(); |
| @GuardedBy("mNetworkStatsLock") |
| private INetworkStatsService mNetworkStatsService; |
| private final Object mThermalLock = new Object(); |
| @GuardedBy("mThermalLock") |
| private IThermalService mThermalService; |
| |
| private final Context mContext; |
| private StatsManager mStatsManager; |
| |
| public StatsPullAtomService(Context context) { |
| super(context); |
| mContext = context; |
| } |
| |
| @Override |
| public void onStart() { |
| mStatsManager = (StatsManager) mContext.getSystemService(Context.STATS_MANAGER); |
| mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); |
| mTelephony = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); |
| |
| // Used to initialize the CPU Frequency atom. |
| PowerProfile powerProfile = new PowerProfile(mContext); |
| final int numClusters = powerProfile.getNumCpuClusters(); |
| mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters]; |
| int firstCpuOfCluster = 0; |
| for (int i = 0; i < numClusters; i++) { |
| final int numSpeedSteps = powerProfile.getNumSpeedStepsInCpuCluster(i); |
| mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster, |
| numSpeedSteps); |
| firstCpuOfCluster += powerProfile.getNumCoresInCpuCluster(i); |
| } |
| } |
| |
| @Override |
| public void onBootPhase(int phase) { |
| super.onBootPhase(phase); |
| if (phase == PHASE_SYSTEM_SERVICES_READY) { |
| BackgroundThread.getHandler().post(() -> { |
| registerAllPullers(); |
| }); |
| } |
| } |
| |
| void registerAllPullers() { |
| if (DEBUG) { |
| Slog.d(TAG, "Registering all pullers with statsd"); |
| } |
| registerWifiBytesTransfer(); |
| registerWifiBytesTransferBackground(); |
| registerMobileBytesTransfer(); |
| registerMobileBytesTransferBackground(); |
| registerBluetoothBytesTransfer(); |
| registerKernelWakelock(); |
| registerCpuTimePerFreq(); |
| registerCpuTimePerUid(); |
| registerCpuTimePerUidFreq(); |
| registerCpuActiveTime(); |
| registerCpuClusterTime(); |
| registerWifiActivityInfo(); |
| registerModemActivityInfo(); |
| registerBluetoothActivityInfo(); |
| registerSystemElapsedRealtime(); |
| registerSystemUptime(); |
| registerRemainingBatteryCapacity(); |
| registerFullBatteryCapacity(); |
| registerBatteryVoltage(); |
| registerBatteryLevel(); |
| registerBatteryCycleCount(); |
| registerProcessMemoryState(); |
| registerProcessMemoryHighWaterMark(); |
| registerProcessMemorySnapshot(); |
| registerSystemIonHeapSize(); |
| registerIonHeapSize(); |
| registerProcessSystemIonHeapSize(); |
| registerTemperature(); |
| registerCoolingDevice(); |
| registerBinderCalls(); |
| registerBinderCallsExceptions(); |
| registerLooperStats(); |
| registerDiskStats(); |
| registerDirectoryUsage(); |
| registerAppSize(); |
| registerCategorySize(); |
| registerNumFingerprintsEnrolled(); |
| registerNumFacesEnrolled(); |
| registerProcStats(); |
| registerProcStatsPkgProc(); |
| registerDiskIO(); |
| registerPowerProfile(); |
| registerProcessCpuTime(); |
| registerCpuTimePerThreadFreq(); |
| registerDeviceCalculatedPowerUse(); |
| registerDeviceCalculatedPowerBlameUid(); |
| registerDeviceCalculatedPowerBlameOther(); |
| registerDebugElapsedClock(); |
| registerDebugFailingElapsedClock(); |
| registerBuildInformation(); |
| registerRoleHolder(); |
| registerDangerousPermissionState(); |
| registerTimeZoneDataInfo(); |
| registerExternalStorageInfo(); |
| registerAppsOnExternalStorageInfo(); |
| registerFaceSettings(); |
| registerAppOps(); |
| registerNotificationRemoteViews(); |
| registerDangerousPermissionState(); |
| registerDangerousPermissionStateSampled(); |
| } |
| |
| private INetworkStatsService getINetworkStatsService() { |
| synchronized (mNetworkStatsLock) { |
| if (mNetworkStatsService == null) { |
| mNetworkStatsService = INetworkStatsService.Stub.asInterface( |
| ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); |
| if (mNetworkStatsService != null) { |
| try { |
| mNetworkStatsService.asBinder().linkToDeath(() -> { |
| synchronized (mNetworkStatsLock) { |
| mNetworkStatsService = null; |
| } |
| }, /* flags */ 0); |
| } catch (RemoteException e) { |
| Slog.e(TAG, "linkToDeath with NetworkStatsService failed", e); |
| mNetworkStatsService = null; |
| } |
| } |
| |
| } |
| return mNetworkStatsService; |
| } |
| } |
| |
| private IThermalService getIThermalService() { |
| synchronized (mThermalLock) { |
| if (mThermalService == null) { |
| mThermalService = IThermalService.Stub.asInterface( |
| ServiceManager.getService(Context.THERMAL_SERVICE)); |
| if (mThermalService != null) { |
| try { |
| mThermalService.asBinder().linkToDeath(() -> { |
| synchronized (mThermalLock) { |
| mThermalService = null; |
| } |
| }, /* flags */ 0); |
| } catch (RemoteException e) { |
| Slog.e(TAG, "linkToDeath with thermalService failed", e); |
| mThermalService = null; |
| } |
| } |
| } |
| return mThermalService; |
| } |
| } |
| private void registerWifiBytesTransfer() { |
| int tagId = StatsLog.WIFI_BYTES_TRANSFER; |
| PullAtomMetadata metadata = PullAtomMetadata.newBuilder() |
| .setAdditiveFields(new int[] {2, 3, 4, 5}) |
| .build(); |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| metadata, |
| (atomTag, data) -> pullWifiBytesTransfer(atomTag, data), |
| Executors.newSingleThreadExecutor() |
| ); |
| } |
| |
| private int pullWifiBytesTransfer(int atomTag, List<StatsEvent> pulledData) { |
| INetworkStatsService networkStatsService = getINetworkStatsService(); |
| if (networkStatsService == null) { |
| Slog.e(TAG, "NetworkStats Service is not available!"); |
| return StatsManager.PULL_SKIP; |
| } |
| long token = Binder.clearCallingIdentity(); |
| try { |
| // TODO: Consider caching the following call to get BatteryStatsInternal. |
| BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); |
| String[] ifaces = bs.getWifiIfaces(); |
| if (ifaces.length == 0) { |
| return StatsManager.PULL_SKIP; |
| } |
| // Combine all the metrics per Uid into one record. |
| NetworkStats stats = networkStatsService.getDetailedUidStats(ifaces).groupedByUid(); |
| addNetworkStats(atomTag, pulledData, stats, false); |
| } catch (RemoteException e) { |
| Slog.e(TAG, "Pulling netstats for wifi bytes has error", e); |
| return StatsManager.PULL_SKIP; |
| } finally { |
| Binder.restoreCallingIdentity(token); |
| } |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void addNetworkStats( |
| int tag, List<StatsEvent> ret, NetworkStats stats, boolean withFGBG) { |
| int size = stats.size(); |
| NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling |
| for (int j = 0; j < size; j++) { |
| stats.getValues(j, entry); |
| StatsEvent.Builder e = StatsEvent.newBuilder(); |
| e.setAtomId(tag); |
| e.writeInt(entry.uid); |
| if (withFGBG) { |
| e.writeInt(entry.set); |
| } |
| e.writeLong(entry.rxBytes); |
| e.writeLong(entry.rxPackets); |
| e.writeLong(entry.txBytes); |
| e.writeLong(entry.txPackets); |
| ret.add(e.build()); |
| } |
| } |
| |
| /** |
| * Allows rollups per UID but keeping the set (foreground/background) slicing. |
| * Adapted from groupedByUid in frameworks/base/core/java/android/net/NetworkStats.java |
| */ |
| private NetworkStats rollupNetworkStatsByFGBG(NetworkStats stats) { |
| final NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1); |
| |
| final NetworkStats.Entry entry = new NetworkStats.Entry(); |
| entry.iface = NetworkStats.IFACE_ALL; |
| entry.tag = NetworkStats.TAG_NONE; |
| entry.metered = NetworkStats.METERED_ALL; |
| entry.roaming = NetworkStats.ROAMING_ALL; |
| |
| int size = stats.size(); |
| NetworkStats.Entry recycle = new NetworkStats.Entry(); // Used for retrieving values |
| for (int i = 0; i < size; i++) { |
| stats.getValues(i, recycle); |
| |
| // Skip specific tags, since already counted in TAG_NONE |
| if (recycle.tag != NetworkStats.TAG_NONE) continue; |
| |
| entry.set = recycle.set; // Allows slicing by background/foreground |
| entry.uid = recycle.uid; |
| entry.rxBytes = recycle.rxBytes; |
| entry.rxPackets = recycle.rxPackets; |
| entry.txBytes = recycle.txBytes; |
| entry.txPackets = recycle.txPackets; |
| // Operations purposefully omitted since we don't use them for statsd. |
| ret.combineValues(entry); |
| } |
| return ret; |
| } |
| |
| private void registerWifiBytesTransferBackground() { |
| int tagId = StatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG; |
| PullAtomMetadata metadata = PullAtomMetadata.newBuilder() |
| .setAdditiveFields(new int[] {3, 4, 5, 6}) |
| .build(); |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| metadata, |
| (atomTag, data) -> pullWifiBytesTransferBackground(atomTag, data), |
| Executors.newSingleThreadExecutor() |
| ); |
| } |
| |
| private int pullWifiBytesTransferBackground(int atomTag, List<StatsEvent> pulledData) { |
| INetworkStatsService networkStatsService = getINetworkStatsService(); |
| if (networkStatsService == null) { |
| Slog.e(TAG, "NetworkStats Service is not available!"); |
| return StatsManager.PULL_SKIP; |
| } |
| long token = Binder.clearCallingIdentity(); |
| try { |
| BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); |
| String[] ifaces = bs.getWifiIfaces(); |
| if (ifaces.length == 0) { |
| return StatsManager.PULL_SKIP; |
| } |
| NetworkStats stats = rollupNetworkStatsByFGBG( |
| networkStatsService.getDetailedUidStats(ifaces)); |
| addNetworkStats(atomTag, pulledData, stats, true); |
| } catch (RemoteException e) { |
| Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e); |
| return StatsManager.PULL_SKIP; |
| } finally { |
| Binder.restoreCallingIdentity(token); |
| } |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void registerMobileBytesTransfer() { |
| int tagId = StatsLog.MOBILE_BYTES_TRANSFER; |
| PullAtomMetadata metadata = PullAtomMetadata.newBuilder() |
| .setAdditiveFields(new int[] {2, 3, 4, 5}) |
| .build(); |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| metadata, |
| (atomTag, data) -> pullMobileBytesTransfer(atomTag, data), |
| Executors.newSingleThreadExecutor() |
| ); |
| } |
| |
| private int pullMobileBytesTransfer(int atomTag, List<StatsEvent> pulledData) { |
| INetworkStatsService networkStatsService = getINetworkStatsService(); |
| if (networkStatsService == null) { |
| Slog.e(TAG, "NetworkStats Service is not available!"); |
| return StatsManager.PULL_SKIP; |
| } |
| long token = Binder.clearCallingIdentity(); |
| try { |
| BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); |
| String[] ifaces = bs.getMobileIfaces(); |
| if (ifaces.length == 0) { |
| return StatsManager.PULL_SKIP; |
| } |
| // Combine all the metrics per Uid into one record. |
| NetworkStats stats = networkStatsService.getDetailedUidStats(ifaces).groupedByUid(); |
| addNetworkStats(atomTag, pulledData, stats, false); |
| } catch (RemoteException e) { |
| Slog.e(TAG, "Pulling netstats for mobile bytes has error", e); |
| return StatsManager.PULL_SKIP; |
| } finally { |
| Binder.restoreCallingIdentity(token); |
| } |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void registerMobileBytesTransferBackground() { |
| int tagId = StatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG; |
| PullAtomMetadata metadata = PullAtomMetadata.newBuilder() |
| .setAdditiveFields(new int[] {3, 4, 5, 6}) |
| .build(); |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| metadata, |
| (atomTag, data) -> pullMobileBytesTransferBackground(atomTag, data), |
| Executors.newSingleThreadExecutor() |
| ); |
| } |
| |
| private int pullMobileBytesTransferBackground(int atomTag, List<StatsEvent> pulledData) { |
| INetworkStatsService networkStatsService = getINetworkStatsService(); |
| if (networkStatsService == null) { |
| Slog.e(TAG, "NetworkStats Service is not available!"); |
| return StatsManager.PULL_SKIP; |
| } |
| long token = Binder.clearCallingIdentity(); |
| try { |
| BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); |
| String[] ifaces = bs.getMobileIfaces(); |
| if (ifaces.length == 0) { |
| return StatsManager.PULL_SKIP; |
| } |
| NetworkStats stats = rollupNetworkStatsByFGBG( |
| networkStatsService.getDetailedUidStats(ifaces)); |
| addNetworkStats(atomTag, pulledData, stats, true); |
| } catch (RemoteException e) { |
| Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e); |
| return StatsManager.PULL_SKIP; |
| } finally { |
| Binder.restoreCallingIdentity(token); |
| } |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void registerBluetoothBytesTransfer() { |
| int tagId = StatsLog.BLUETOOTH_BYTES_TRANSFER; |
| PullAtomMetadata metadata = PullAtomMetadata.newBuilder() |
| .setAdditiveFields(new int[] {2, 3}) |
| .build(); |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| metadata, |
| (atomTag, data) -> pullBluetoothBytesTransfer(atomTag, data), |
| Executors.newSingleThreadExecutor() |
| ); |
| } |
| |
| /** |
| * Helper method to extract the Parcelable controller info from a |
| * SynchronousResultReceiver. |
| */ |
| private static <T extends Parcelable> T awaitControllerInfo( |
| @Nullable SynchronousResultReceiver receiver) { |
| if (receiver == null) { |
| return null; |
| } |
| |
| try { |
| final SynchronousResultReceiver.Result result = |
| receiver.awaitResult(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS); |
| if (result.bundle != null) { |
| // This is the final destination for the Bundle. |
| result.bundle.setDefusable(true); |
| |
| final T data = result.bundle.getParcelable(RESULT_RECEIVER_CONTROLLER_KEY); |
| if (data != null) { |
| return data; |
| } |
| } |
| Slog.e(TAG, "no controller energy info supplied for " + receiver.getName()); |
| } catch (TimeoutException e) { |
| Slog.w(TAG, "timeout reading " + receiver.getName() + " stats"); |
| } |
| return null; |
| } |
| |
| private synchronized BluetoothActivityEnergyInfo fetchBluetoothData() { |
| // TODO: Investigate whether the synchronized keyword is needed. |
| final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); |
| if (adapter != null) { |
| SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver( |
| "bluetooth"); |
| adapter.requestControllerActivityEnergyInfo(bluetoothReceiver); |
| return awaitControllerInfo(bluetoothReceiver); |
| } else { |
| Slog.e(TAG, "Failed to get bluetooth adapter!"); |
| return null; |
| } |
| } |
| |
| private int pullBluetoothBytesTransfer(int atomTag, List<StatsEvent> pulledData) { |
| BluetoothActivityEnergyInfo info = fetchBluetoothData(); |
| if (info == null || info.getUidTraffic() == null) { |
| return StatsManager.PULL_SKIP; |
| } |
| for (UidTraffic traffic : info.getUidTraffic()) { |
| StatsEvent e = StatsEvent.newBuilder() |
| .setAtomId(atomTag) |
| .writeInt(traffic.getUid()) |
| .writeLong(traffic.getRxBytes()) |
| .writeLong(traffic.getTxBytes()) |
| .build(); |
| pulledData.add(e); |
| } |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader(); |
| private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats(); |
| |
| private void registerKernelWakelock() { |
| int tagId = StatsLog.KERNEL_WAKELOCK; |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| /* PullAtomMetadata */ null, |
| (atomTag, data) -> pullKernelWakelock(atomTag, data), |
| Executors.newSingleThreadExecutor() |
| ); |
| } |
| |
| private int pullKernelWakelock(int atomTag, List<StatsEvent> pulledData) { |
| final KernelWakelockStats wakelockStats = |
| mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats); |
| for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) { |
| String name = ent.getKey(); |
| KernelWakelockStats.Entry kws = ent.getValue(); |
| StatsEvent e = StatsEvent.newBuilder() |
| .setAtomId(atomTag) |
| .writeString(name) |
| .writeInt(kws.mCount) |
| .writeInt(kws.mVersion) |
| .writeLong(kws.mTotalTime) |
| .build(); |
| pulledData.add(e); |
| } |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private KernelCpuSpeedReader[] mKernelCpuSpeedReaders; |
| // Disables throttler on CPU time readers. |
| private KernelCpuUidUserSysTimeReader mCpuUidUserSysTimeReader = |
| new KernelCpuUidUserSysTimeReader(false); |
| private KernelCpuUidFreqTimeReader mCpuUidFreqTimeReader = |
| new KernelCpuUidFreqTimeReader(false); |
| private KernelCpuUidActiveTimeReader mCpuUidActiveTimeReader = |
| new KernelCpuUidActiveTimeReader(false); |
| private KernelCpuUidClusterTimeReader mCpuUidClusterTimeReader = |
| new KernelCpuUidClusterTimeReader(false); |
| |
| private void registerCpuTimePerFreq() { |
| int tagId = StatsLog.CPU_TIME_PER_FREQ; |
| PullAtomMetadata metadata = PullAtomMetadata.newBuilder() |
| .setAdditiveFields(new int[] {3}) |
| .build(); |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| metadata, |
| (atomTag, data) -> pullCpuTimePerFreq(atomTag, data), |
| Executors.newSingleThreadExecutor() |
| ); |
| } |
| |
| private int pullCpuTimePerFreq(int atomTag, List<StatsEvent> pulledData) { |
| for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) { |
| long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute(); |
| if (clusterTimeMs != null) { |
| for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) { |
| StatsEvent e = StatsEvent.newBuilder() |
| .setAtomId(atomTag) |
| .writeInt(cluster) |
| .writeInt(speed) |
| .writeLong(clusterTimeMs[speed]) |
| .build(); |
| pulledData.add(e); |
| } |
| } |
| } |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void registerCpuTimePerUid() { |
| int tagId = StatsLog.CPU_TIME_PER_UID; |
| PullAtomMetadata metadata = PullAtomMetadata.newBuilder() |
| .setAdditiveFields(new int[] {2, 3}) |
| .build(); |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| metadata, |
| (atomTag, data) -> pullCpuTimePerUid(atomTag, data), |
| Executors.newSingleThreadExecutor() |
| ); |
| } |
| |
| private int pullCpuTimePerUid(int atomTag, List<StatsEvent> pulledData) { |
| mCpuUidUserSysTimeReader.readAbsolute((uid, timesUs) -> { |
| long userTimeUs = timesUs[0], systemTimeUs = timesUs[1]; |
| StatsEvent e = StatsEvent.newBuilder() |
| .setAtomId(atomTag) |
| .writeInt(uid) |
| .writeLong(userTimeUs) |
| .writeLong(systemTimeUs) |
| .build(); |
| pulledData.add(e); |
| }); |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void registerCpuTimePerUidFreq() { |
| // the throttling is 3sec, handled in |
| // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader |
| int tagId = StatsLog.CPU_TIME_PER_UID_FREQ; |
| PullAtomMetadata metadata = PullAtomMetadata.newBuilder() |
| .setAdditiveFields(new int[] {4}) |
| .build(); |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| metadata, |
| (atomTag, data) -> pullCpuTimeperUidFreq(atomTag, data), |
| Executors.newSingleThreadExecutor() |
| ); |
| } |
| |
| private int pullCpuTimeperUidFreq(int atomTag, List<StatsEvent> pulledData) { |
| mCpuUidFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> { |
| for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) { |
| if (cpuFreqTimeMs[freqIndex] != 0) { |
| StatsEvent e = StatsEvent.newBuilder() |
| .setAtomId(atomTag) |
| .writeInt(uid) |
| .writeInt(freqIndex) |
| .writeLong(cpuFreqTimeMs[freqIndex]) |
| .build(); |
| pulledData.add(e); |
| } |
| } |
| }); |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void registerCpuActiveTime() { |
| // the throttling is 3sec, handled in |
| // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader |
| int tagId = StatsLog.CPU_ACTIVE_TIME; |
| PullAtomMetadata metadata = PullAtomMetadata.newBuilder() |
| .setAdditiveFields(new int[] {2}) |
| .build(); |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| metadata, |
| (atomTag, data) -> pullCpuActiveTime(atomTag, data), |
| Executors.newSingleThreadExecutor() |
| ); |
| } |
| |
| private int pullCpuActiveTime(int atomTag, List<StatsEvent> pulledData) { |
| mCpuUidActiveTimeReader.readAbsolute((uid, cpuActiveTimesMs) -> { |
| StatsEvent e = StatsEvent.newBuilder() |
| .setAtomId(atomTag) |
| .writeInt(uid) |
| .writeLong(cpuActiveTimesMs) |
| .build(); |
| pulledData.add(e); |
| }); |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void registerCpuClusterTime() { |
| // the throttling is 3sec, handled in |
| // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader |
| int tagId = StatsLog.CPU_CLUSTER_TIME; |
| PullAtomMetadata metadata = PullAtomMetadata.newBuilder() |
| .setAdditiveFields(new int[] {3}) |
| .build(); |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| metadata, |
| (atomTag, data) -> pullCpuClusterTime(atomTag, data), |
| Executors.newSingleThreadExecutor() |
| ); |
| } |
| |
| private int pullCpuClusterTime(int atomTag, List<StatsEvent> pulledData) { |
| mCpuUidClusterTimeReader.readAbsolute((uid, cpuClusterTimesMs) -> { |
| for (int i = 0; i < cpuClusterTimesMs.length; i++) { |
| StatsEvent e = StatsEvent.newBuilder() |
| .setAtomId(atomTag) |
| .writeInt(uid) |
| .writeInt(i) |
| .writeLong(cpuClusterTimesMs[i]) |
| .build(); |
| pulledData.add(e); |
| } |
| }); |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void registerWifiActivityInfo() { |
| int tagId = StatsLog.WIFI_ACTIVITY_INFO; |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| null, // use default PullAtomMetadata values |
| (atomTag, data) -> pullWifiActivityInfo(atomTag, data), |
| BackgroundThread.getExecutor() |
| ); |
| } |
| |
| private WifiManager mWifiManager; |
| private TelephonyManager mTelephony; |
| |
| private int pullWifiActivityInfo(int atomTag, List<StatsEvent> pulledData) { |
| long token = Binder.clearCallingIdentity(); |
| try { |
| SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi"); |
| mWifiManager.getWifiActivityEnergyInfoAsync( |
| new Executor() { |
| @Override |
| public void execute(Runnable runnable) { |
| // run the listener on the binder thread, if it was run on the main |
| // thread it would deadlock since we would be waiting on ourselves |
| runnable.run(); |
| } |
| }, |
| info -> { |
| Bundle bundle = new Bundle(); |
| bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, info); |
| wifiReceiver.send(0, bundle); |
| } |
| ); |
| final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver); |
| if (wifiInfo == null) { |
| return StatsManager.PULL_SKIP; |
| } |
| StatsEvent e = StatsEvent.newBuilder() |
| .setAtomId(atomTag) |
| .writeLong(wifiInfo.getTimeSinceBootMillis()) |
| .writeInt(wifiInfo.getStackState()) |
| .writeLong(wifiInfo.getControllerTxDurationMillis()) |
| .writeLong(wifiInfo.getControllerRxDurationMillis()) |
| .writeLong(wifiInfo.getControllerIdleDurationMillis()) |
| .writeLong(wifiInfo.getControllerEnergyUsedMicroJoules()) |
| .build(); |
| pulledData.add(e); |
| } catch (RuntimeException e) { |
| Slog.e(TAG, "failed to getWifiActivityEnergyInfoAsync", e); |
| return StatsManager.PULL_SKIP; |
| } finally { |
| Binder.restoreCallingIdentity(token); |
| } |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void registerModemActivityInfo() { |
| int tagId = StatsLog.MODEM_ACTIVITY_INFO; |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| null, // use default PullAtomMetadata values |
| (atomTag, data) -> pullModemActivityInfo(atomTag, data), |
| BackgroundThread.getExecutor() |
| ); |
| } |
| |
| private int pullModemActivityInfo(int atomTag, List<StatsEvent> pulledData) { |
| long token = Binder.clearCallingIdentity(); |
| try { |
| SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony"); |
| mTelephony.requestModemActivityInfo(modemReceiver); |
| final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver); |
| if (modemInfo == null) { |
| return StatsManager.PULL_SKIP; |
| } |
| StatsEvent e = StatsEvent.newBuilder() |
| .setAtomId(atomTag) |
| .writeLong(modemInfo.getTimestamp()) |
| .writeLong(modemInfo.getSleepTimeMillis()) |
| .writeLong(modemInfo.getIdleTimeMillis()) |
| .writeLong(modemInfo.getTransmitPowerInfo().get(0).getTimeInMillis()) |
| .writeLong(modemInfo.getTransmitPowerInfo().get(1).getTimeInMillis()) |
| .writeLong(modemInfo.getTransmitPowerInfo().get(2).getTimeInMillis()) |
| .writeLong(modemInfo.getTransmitPowerInfo().get(3).getTimeInMillis()) |
| .writeLong(modemInfo.getTransmitPowerInfo().get(4).getTimeInMillis()) |
| .writeLong(modemInfo.getReceiveTimeMillis()) |
| .build(); |
| pulledData.add(e); |
| } finally { |
| Binder.restoreCallingIdentity(token); |
| } |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void registerBluetoothActivityInfo() { |
| int tagId = StatsLog.BLUETOOTH_ACTIVITY_INFO; |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| /* metadata */ null, |
| (atomTag, data) -> pullBluetoothActivityInfo(atomTag, data), |
| Executors.newSingleThreadExecutor() |
| ); |
| } |
| |
| private int pullBluetoothActivityInfo(int atomTag, List<StatsEvent> pulledData) { |
| BluetoothActivityEnergyInfo info = fetchBluetoothData(); |
| if (info == null) { |
| return StatsManager.PULL_SKIP; |
| } |
| StatsEvent e = StatsEvent.newBuilder() |
| .setAtomId(atomTag) |
| .writeLong(info.getTimeStamp()) |
| .writeInt(info.getBluetoothStackState()) |
| .writeLong(info.getControllerTxTimeMillis()) |
| .writeLong(info.getControllerRxTimeMillis()) |
| .writeLong(info.getControllerIdleTimeMillis()) |
| .writeLong(info.getControllerEnergyUsed()) |
| .build(); |
| pulledData.add(e); |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void registerSystemElapsedRealtime() { |
| // No op. |
| } |
| |
| private void pullSystemElapsedRealtime() { |
| // No op. |
| } |
| |
| private void registerSystemUptime() { |
| int tagId = StatsLog.SYSTEM_UPTIME; |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| null, // use default PullAtomMetadata values |
| (atomTag, data) -> pullSystemUptime(atomTag, data), |
| Executors.newSingleThreadExecutor() |
| ); |
| } |
| |
| private int pullSystemUptime(int atomTag, List<StatsEvent> pulledData) { |
| StatsEvent e = StatsEvent.newBuilder() |
| .setAtomId(atomTag) |
| .writeLong(SystemClock.elapsedRealtime()) |
| .build(); |
| pulledData.add(e); |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void registerRemainingBatteryCapacity() { |
| // No op. |
| } |
| |
| private void pullRemainingBatteryCapacity() { |
| // No op. |
| } |
| |
| private void registerFullBatteryCapacity() { |
| // No op. |
| } |
| |
| private void pullFullBatteryCapacity() { |
| // No op. |
| } |
| |
| private void registerBatteryVoltage() { |
| // No op. |
| } |
| |
| private void pullBatteryVoltage() { |
| // No op. |
| } |
| |
| private void registerBatteryLevel() { |
| // No op. |
| } |
| |
| private void pullBatteryLevel() { |
| // No op. |
| } |
| |
| private void registerBatteryCycleCount() { |
| // No op. |
| } |
| |
| private void pullBatteryCycleCount() { |
| // No op. |
| } |
| |
| private void registerProcessMemoryState() { |
| // No op. |
| } |
| |
| private void pullProcessMemoryState() { |
| // No op. |
| } |
| |
| private void registerProcessMemoryHighWaterMark() { |
| // No op. |
| } |
| |
| private void pullProcessMemoryHighWaterMark() { |
| // No op. |
| } |
| |
| private void registerProcessMemorySnapshot() { |
| // No op. |
| } |
| |
| private void pullProcessMemorySnapshot() { |
| // No op. |
| } |
| |
| private void registerSystemIonHeapSize() { |
| // No op. |
| } |
| |
| private void pullSystemIonHeapSize() { |
| // No op. |
| } |
| |
| private void registerIonHeapSize() { |
| int tagId = StatsLog.ION_HEAP_SIZE; |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| /* PullAtomMetadata */ null, |
| (atomTag, data) -> pullIonHeapSize(atomTag, data), |
| Executors.newSingleThreadExecutor() |
| ); |
| } |
| |
| private int pullIonHeapSize(int atomTag, List<StatsEvent> pulledData) { |
| int ionHeapSizeInKilobytes = (int) getIonHeapsSizeKb(); |
| StatsEvent e = StatsEvent.newBuilder() |
| .setAtomId(atomTag) |
| .writeInt(ionHeapSizeInKilobytes) |
| .build(); |
| pulledData.add(e); |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void registerProcessSystemIonHeapSize() { |
| // No op. |
| } |
| |
| private void pullProcessSystemIonHeapSize() { |
| // No op. |
| } |
| |
| private void registerTemperature() { |
| // No op. |
| } |
| |
| private void pullTemperature() { |
| // No op. |
| } |
| |
| private void registerCoolingDevice() { |
| // No op. |
| } |
| |
| private void pullCooldownDevice() { |
| // No op. |
| } |
| |
| private void registerBinderCalls() { |
| // No op. |
| } |
| |
| private void pullBinderCalls() { |
| // No op. |
| } |
| |
| private void registerBinderCallsExceptions() { |
| // No op. |
| } |
| |
| private void pullBinderCallsExceptions() { |
| // No op. |
| } |
| |
| private void registerLooperStats() { |
| // No op. |
| } |
| |
| private void pullLooperStats() { |
| // No op. |
| } |
| |
| private void registerDiskStats() { |
| // No op. |
| } |
| |
| private void pullDiskStats() { |
| // No op. |
| } |
| |
| private void registerDirectoryUsage() { |
| // No op. |
| } |
| |
| private void pullDirectoryUsage() { |
| // No op. |
| } |
| |
| private void registerAppSize() { |
| // No op. |
| } |
| |
| private void pullAppSize() { |
| // No op. |
| } |
| |
| private void registerCategorySize() { |
| // No op. |
| } |
| |
| private void pullCategorySize() { |
| // No op. |
| } |
| |
| private void registerNumFingerprintsEnrolled() { |
| // No op. |
| } |
| |
| private void pullNumFingerprintsEnrolled() { |
| // No op. |
| } |
| |
| private void registerNumFacesEnrolled() { |
| // No op. |
| } |
| |
| private void pullNumFacesEnrolled() { |
| // No op. |
| } |
| |
| private void registerProcStats() { |
| // No op. |
| } |
| |
| private void pullProcStats() { |
| // No op. |
| } |
| |
| private void registerProcStatsPkgProc() { |
| // No op. |
| } |
| |
| private void pullProcStatsPkgProc() { |
| // No op. |
| } |
| |
| private void registerDiskIO() { |
| // No op. |
| } |
| |
| private void pullDiskIO() { |
| // No op. |
| } |
| |
| private void registerPowerProfile() { |
| int tagId = StatsLog.POWER_PROFILE; |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| /* PullAtomMetadata */ null, |
| (atomTag, data) -> pullPowerProfile(atomTag, data), |
| Executors.newSingleThreadExecutor() |
| ); |
| } |
| |
| private int pullPowerProfile(int atomTag, List<StatsEvent> pulledData) { |
| PowerProfile powerProfile = new PowerProfile(mContext); |
| ProtoOutputStream proto = new ProtoOutputStream(); |
| powerProfile.dumpDebug(proto); |
| proto.flush(); |
| StatsEvent e = StatsEvent.newBuilder() |
| .setAtomId(atomTag) |
| .writeByteArray(proto.getBytes()) |
| .build(); |
| pulledData.add(e); |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void registerProcessCpuTime() { |
| // No op. |
| } |
| |
| private void pullProcessCpuTime() { |
| // No op. |
| } |
| |
| private void registerCpuTimePerThreadFreq() { |
| // No op. |
| } |
| |
| private void pullCpuTimePerThreadFreq() { |
| // No op. |
| } |
| |
| private void registerDeviceCalculatedPowerUse() { |
| // No op. |
| } |
| |
| private void pullDeviceCalculatedPowerUse() { |
| // No op. |
| } |
| |
| private void registerDeviceCalculatedPowerBlameUid() { |
| // No op. |
| } |
| |
| private void pullDeviceCalculatedPowerBlameUid() { |
| // No op. |
| } |
| |
| private void registerDeviceCalculatedPowerBlameOther() { |
| // No op. |
| } |
| |
| private void pullDeviceCalculatedPowerBlameOther() { |
| // No op. |
| } |
| |
| private void registerDebugElapsedClock() { |
| // No op. |
| } |
| |
| private void pullDebugElapsedClock() { |
| // No op. |
| } |
| |
| private void registerDebugFailingElapsedClock() { |
| // No op. |
| } |
| |
| private void pullDebugFailingElapsedClock() { |
| // No op. |
| } |
| |
| private void registerBuildInformation() { |
| int tagId = StatsLog.BUILD_INFORMATION; |
| mStatsManager.registerPullAtomCallback( |
| tagId, |
| null, // use default PullAtomMetadata values |
| (atomTag, data) -> pullBuildInformation(atomTag, data), |
| BackgroundThread.getExecutor() |
| ); |
| } |
| |
| private int pullBuildInformation(int atomTag, List<StatsEvent> pulledData) { |
| StatsEvent e = StatsEvent.newBuilder() |
| .setAtomId(atomTag) |
| .writeString(Build.FINGERPRINT) |
| .writeString(Build.BRAND) |
| .writeString(Build.PRODUCT) |
| .writeString(Build.DEVICE) |
| .writeString(Build.VERSION.RELEASE) |
| .writeString(Build.ID) |
| .writeString(Build.VERSION.INCREMENTAL) |
| .writeString(Build.TYPE) |
| .writeString(Build.TAGS) |
| .build(); |
| pulledData.add(e); |
| return StatsManager.PULL_SUCCESS; |
| } |
| |
| private void registerRoleHolder() { |
| // No op. |
| } |
| |
| private void pullRoleHolder() { |
| // No op. |
| } |
| |
| private void registerDangerousPermissionState() { |
| // No op. |
| } |
| |
| private void pullDangerousPermissionState() { |
| // No op. |
| } |
| |
| private void registerTimeZoneDataInfo() { |
| // No op. |
| } |
| |
| private void pullTimeZoneDataInfo() { |
| // No op. |
| } |
| |
| private void registerExternalStorageInfo() { |
| // No op. |
| } |
| |
| private void pullExternalStorageInfo() { |
| // No op. |
| } |
| |
| private void registerAppsOnExternalStorageInfo() { |
| // No op. |
| } |
| |
| private void pullAppsOnExternalStorageInfo() { |
| // No op. |
| } |
| |
| private void registerFaceSettings() { |
| // No op. |
| } |
| |
| private void pullRegisterFaceSettings() { |
| // No op. |
| } |
| |
| private void registerAppOps() { |
| // No op. |
| } |
| |
| private void pullAppOps() { |
| // No op. |
| } |
| |
| private void registerNotificationRemoteViews() { |
| // No op. |
| } |
| |
| private void pullNotificationRemoteViews() { |
| // No op. |
| } |
| |
| private void registerDangerousPermissionStateSampled() { |
| // No op. |
| } |
| |
| private void pullDangerousPermissionStateSampled() { |
| // No op. |
| } |
| } |