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 package com.android.server.power.batterysaver; 17 18 import android.util.ArrayMap; 19 import android.util.Slog; 20 21 import com.android.internal.annotations.GuardedBy; 22 23 import java.util.Map; 24 25 26 /** 27 * Helper to parse a list of "core-number:frequency" pairs concatenated with / as a separator, 28 * and convert them into a map of "filename -> value" that should be written to 29 * /sys/.../scaling_max_freq. 30 * 31 * Example input: "0:1900800/4:2500000", which will be converted into: 32 * "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq" "1900800" 33 * "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq" "2500000" 34 * 35 * Test: 36 atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/power/batterysaver/CpuFrequenciesTest.java 37 */ 38 public class CpuFrequencies { 39 private static final String TAG = "CpuFrequencies"; 40 41 private final Object mLock = new Object(); 42 43 @GuardedBy("mLock") 44 private final ArrayMap<Integer, Long> mCoreAndFrequencies = new ArrayMap<>(); 45 CpuFrequencies()46 public CpuFrequencies() { 47 } 48 49 /** 50 * Parse a string. 51 */ parseString(String cpuNumberAndFrequencies)52 public CpuFrequencies parseString(String cpuNumberAndFrequencies) { 53 synchronized (mLock) { 54 mCoreAndFrequencies.clear(); 55 try { 56 for (String pair : cpuNumberAndFrequencies.split("/")) { 57 pair = pair.trim(); 58 if (pair.length() == 0) { 59 continue; 60 } 61 final String[] coreAndFreq = pair.split(":", 2); 62 63 if (coreAndFreq.length != 2) { 64 throw new IllegalArgumentException("Wrong format"); 65 } 66 final int core = Integer.parseInt(coreAndFreq[0]); 67 final long freq = Long.parseLong(coreAndFreq[1]); 68 69 mCoreAndFrequencies.put(core, freq); 70 } 71 } catch (IllegalArgumentException e) { 72 Slog.wtf(TAG, "Invalid configuration: '" + cpuNumberAndFrequencies + "'"); 73 } 74 } 75 return this; 76 } 77 78 /** 79 * Return a new map containing the filename-value pairs. 80 */ toSysFileMap()81 public ArrayMap<String, String> toSysFileMap() { 82 final ArrayMap<String, String> map = new ArrayMap<>(); 83 addToSysFileMap(map); 84 return map; 85 } 86 87 /** 88 * Add the filename-value pairs to an existing map. 89 */ addToSysFileMap(Map<String, String> map)90 public void addToSysFileMap(Map<String, String> map) { 91 synchronized (mLock) { 92 final int size = mCoreAndFrequencies.size(); 93 94 for (int i = 0; i < size; i++) { 95 final int core = mCoreAndFrequencies.keyAt(i); 96 final long freq = mCoreAndFrequencies.valueAt(i); 97 98 final String file = "/sys/devices/system/cpu/cpu" + Integer.toString(core) + 99 "/cpufreq/scaling_max_freq"; 100 101 map.put(file, Long.toString(freq)); 102 } 103 } 104 } 105 } 106