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 static final String CPU_DELIM = "/"; 42 private static final String FREQUENCY_DELIM = ":"; 43 private final Object mLock = new Object(); 44 45 @GuardedBy("mLock") 46 private final ArrayMap<Integer, Long> mCoreAndFrequencies = new ArrayMap<>(); 47 CpuFrequencies()48 public CpuFrequencies() { 49 } 50 51 /** 52 * Parse a string. 53 */ parseString(String cpuNumberAndFrequencies)54 public CpuFrequencies parseString(String cpuNumberAndFrequencies) { 55 synchronized (mLock) { 56 mCoreAndFrequencies.clear(); 57 try { 58 for (String pair : cpuNumberAndFrequencies.split(CPU_DELIM)) { 59 pair = pair.trim(); 60 if (pair.length() == 0) { 61 continue; 62 } 63 final String[] coreAndFreq = pair.split(FREQUENCY_DELIM, 2); 64 65 if (coreAndFreq.length != 2) { 66 throw new IllegalArgumentException("Wrong format"); 67 } 68 final int core = Integer.parseInt(coreAndFreq[0]); 69 final long freq = Long.parseLong(coreAndFreq[1]); 70 71 mCoreAndFrequencies.put(core, freq); 72 } 73 } catch (IllegalArgumentException e) { 74 Slog.wtf(TAG, "Invalid configuration: '" + cpuNumberAndFrequencies + "'"); 75 } 76 } 77 return this; 78 } 79 80 /** 81 * Return a new map containing the filename-value pairs. 82 */ toSysFileMap()83 public ArrayMap<String, String> toSysFileMap() { 84 final ArrayMap<String, String> map = new ArrayMap<>(); 85 addToSysFileMap(map); 86 return map; 87 } 88 89 /** 90 * Add the filename-value pairs to an existing map. 91 */ addToSysFileMap(Map<String, String> map)92 public void addToSysFileMap(Map<String, String> map) { 93 synchronized (mLock) { 94 final int size = mCoreAndFrequencies.size(); 95 96 for (int i = 0; i < size; i++) { 97 final int core = mCoreAndFrequencies.keyAt(i); 98 final long freq = mCoreAndFrequencies.valueAt(i); 99 100 final String file = "/sys/devices/system/cpu/cpu" + Integer.toString(core) + 101 "/cpufreq/scaling_max_freq"; 102 103 map.put(file, Long.toString(freq)); 104 } 105 } 106 } 107 108 /** 109 * Returns String describing the frequency settings used. 110 * The returned String can be parsed again by {@link #parseString(String)}. 111 */ toString()112 public String toString() { 113 synchronized (mLock) { 114 StringBuilder sb = new StringBuilder(); 115 for (int i = 0; i < mCoreAndFrequencies.size(); i++) { 116 if (i > 0) { 117 sb.append(CPU_DELIM); 118 } 119 sb.append(mCoreAndFrequencies.keyAt(i)); 120 sb.append(FREQUENCY_DELIM); 121 sb.append(mCoreAndFrequencies.valueAt(i)); 122 } 123 124 return sb.toString(); 125 } 126 } 127 128 @Override equals(Object obj)129 public boolean equals(Object obj) { 130 synchronized (mLock) { 131 if (this == obj) return true; 132 if (!(obj instanceof CpuFrequencies)) return false; 133 CpuFrequencies other = (CpuFrequencies) obj; 134 return mCoreAndFrequencies.equals(other.mCoreAndFrequencies); 135 } 136 } 137 138 @Override hashCode()139 public int hashCode() { 140 return mCoreAndFrequencies.hashCode(); 141 } 142 } 143