1 /* 2 * Copyright (C) 2023 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.tv.settings.device.eco; 18 19 import android.app.job.JobInfo; 20 import android.app.job.JobParameters; 21 import android.app.job.JobScheduler; 22 import android.app.job.JobService; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.pm.PackageManager; 26 import android.os.PowerManager.LowPowerStandbyPolicy; 27 import android.util.ArraySet; 28 import android.util.Log; 29 30 import com.android.settingslib.utils.ThreadUtils; 31 import com.android.tv.settings.R; 32 import com.android.tv.settings.device.eco.EnergyModesHelper.EnergyMode; 33 import com.android.tv.twopanelsettings.slices.TvSettingsStatsLog; 34 35 import java.util.Arrays; 36 import java.util.List; 37 import java.util.concurrent.TimeUnit; 38 39 /** 40 * JobService to log available energy mode policies. 41 */ 42 public class EnergyModesStatsLogJobService extends JobService { 43 private static final String TAG = "EnergyModesStatsLogJobService"; 44 private static final long WRITE_STATS_FREQUENCY_MS = TimeUnit.DAYS.toMillis(6); 45 46 /** Schedule a periodic job to log available energy mode policies. */ scheduleEnergyModesStatsLog(Context context)47 public static void scheduleEnergyModesStatsLog(Context context) { 48 final EnergyModesHelper energyModesHelper = new EnergyModesHelper(context); 49 if (!energyModesHelper.areEnergyModesAvailable()) { 50 return; 51 } 52 53 final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); 54 final ComponentName component = 55 new ComponentName(context, EnergyModesStatsLogJobService.class); 56 final JobInfo job = 57 new JobInfo.Builder(R.integer.job_energy_modes_stats_log, component) 58 .setPeriodic(WRITE_STATS_FREQUENCY_MS) 59 .setRequiresDeviceIdle(true) 60 .setPersisted(true) 61 .build(); 62 final JobInfo pending = jobScheduler.getPendingJob(R.integer.job_energy_modes_stats_log); 63 64 // Don't schedule it if it already exists, to make sure it runs periodically even after 65 // reboot 66 if (pending == null && jobScheduler.schedule(job) != JobScheduler.RESULT_SUCCESS) { 67 Log.i(TAG, "Energy Modes stats log job service schedule failed."); 68 } 69 } 70 71 @Override onStartJob(JobParameters params)72 public boolean onStartJob(JobParameters params) { 73 ThreadUtils.postOnBackgroundThread(() -> { 74 writePoliciesStatsLog(getApplicationContext()); 75 jobFinished(params, false /* wantsReschedule */); 76 }); 77 78 return true; 79 } 80 81 @Override onStopJob(JobParameters jobParameters)82 public boolean onStopJob(JobParameters jobParameters) { 83 return false; 84 } 85 86 /** Writes available energy mode policies to stats log */ writePoliciesStatsLog(Context context)87 public static void writePoliciesStatsLog(Context context) { 88 final EnergyModesHelper energyModesHelper = new EnergyModesHelper(context); 89 final EnergyMode current = energyModesHelper.updateEnergyMode(); 90 final List<EnergyMode> energyModes = energyModesHelper.getEnergyModes(); 91 92 for (EnergyMode energyMode : energyModes) { 93 final LowPowerStandbyPolicy policy = energyModesHelper.getPolicy(energyMode); 94 TvSettingsStatsLog.write( 95 TvSettingsStatsLog.TV_LOW_POWER_STANDBY_POLICY, 96 policy.getIdentifier(), 97 getExemptPackageUids(context, policy), 98 policy.getAllowedReasons(), 99 policy.getAllowedFeatures().toArray(new String[0]), 100 energyMode == current 101 ); 102 } 103 } 104 getExemptPackageUids(Context context, LowPowerStandbyPolicy policy)105 private static int[] getExemptPackageUids(Context context, LowPowerStandbyPolicy policy) { 106 final PackageManager packageManager = context.getPackageManager(); 107 final ArraySet<Integer> exemptUids = new ArraySet<>(); 108 for (String exemptPackage : policy.getExemptPackages()) { 109 try { 110 int uid = packageManager.getPackageUid(exemptPackage, PackageManager.MATCH_ALL); 111 exemptUids.add(uid); 112 } catch (PackageManager.NameNotFoundException e) { 113 } 114 } 115 116 final int[] exemptUidsArray = new int[exemptUids.size()]; 117 int i = 0; 118 for (Integer uid : exemptUids) { 119 exemptUidsArray[i++] = uid; 120 } 121 122 Arrays.sort(exemptUidsArray); 123 return exemptUidsArray; 124 } 125 } 126