1ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki/*
2ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki * Copyright (C) 2017 The Android Open Source Project
3ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki *
4ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki * Licensed under the Apache License, Version 2.0 (the "License");
5ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki * you may not use this file except in compliance with the License.
6ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki * You may obtain a copy of the License at
7ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki *
8ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki *      http://www.apache.org/licenses/LICENSE-2.0
9ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki *
10ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki * Unless required by applicable law or agreed to in writing, software
11ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki * distributed under the License is distributed on an "AS IS" BASIS,
12ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki * See the License for the specific language governing permissions and
14ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki * limitations under the License.
15ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki */
16ce643a309e8d414395ec36188523d10eb64d6618Makoto Onukipackage com.android.server.power.batterysaver;
17ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
18ce643a309e8d414395ec36188523d10eb64d6618Makoto Onukiimport android.util.ArrayMap;
19ce643a309e8d414395ec36188523d10eb64d6618Makoto Onukiimport android.util.Slog;
20ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
21ce643a309e8d414395ec36188523d10eb64d6618Makoto Onukiimport com.android.internal.annotations.GuardedBy;
22ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
23ce643a309e8d414395ec36188523d10eb64d6618Makoto Onukiimport java.util.Map;
24ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
25ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
26ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki/**
27ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki * Helper to parse a list of "core-number:frequency" pairs concatenated with / as a separator,
28ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki * and convert them into a map of "filename -> value" that should be written to
29ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki * /sys/.../scaling_max_freq.
30ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki *
31ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki * Example input: "0:1900800/4:2500000", which will be converted into:
32ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki *   "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq" "1900800"
33ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki *   "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq" "2500000"
34ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki *
35ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki * Test:
36ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/power/batterysaver/CpuFrequenciesTest.java
37ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki */
38ce643a309e8d414395ec36188523d10eb64d6618Makoto Onukipublic class CpuFrequencies {
39ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki    private static final String TAG = "CpuFrequencies";
40ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
41ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki    private final Object mLock = new Object();
42ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
43ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki    @GuardedBy("mLock")
44ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki    private final ArrayMap<Integer, Long> mCoreAndFrequencies = new ArrayMap<>();
45ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
46ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki    public CpuFrequencies() {
47ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki    }
48ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
49ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki    /**
50ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki     * Parse a string.
51ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki     */
52ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki    public CpuFrequencies parseString(String cpuNumberAndFrequencies) {
53ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki        synchronized (mLock) {
54ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki            mCoreAndFrequencies.clear();
55ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki            try {
56ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki                for (String pair : cpuNumberAndFrequencies.split("/")) {
57afd6ff30816afc545cde4191d4eb56527ce207d6Makoto Onuki                    pair = pair.trim();
58afd6ff30816afc545cde4191d4eb56527ce207d6Makoto Onuki                    if (pair.length() == 0) {
59afd6ff30816afc545cde4191d4eb56527ce207d6Makoto Onuki                        continue;
60afd6ff30816afc545cde4191d4eb56527ce207d6Makoto Onuki                    }
61ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki                    final String[] coreAndFreq = pair.split(":", 2);
62ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
63ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki                    if (coreAndFreq.length != 2) {
64ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki                        throw new IllegalArgumentException("Wrong format");
65ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki                    }
66ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki                    final int core = Integer.parseInt(coreAndFreq[0]);
67ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki                    final long freq = Long.parseLong(coreAndFreq[1]);
68ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
69ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki                    mCoreAndFrequencies.put(core, freq);
70ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki                }
71ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki            } catch (IllegalArgumentException e) {
72afd6ff30816afc545cde4191d4eb56527ce207d6Makoto Onuki                Slog.wtf(TAG, "Invalid configuration: '" + cpuNumberAndFrequencies + "'");
73ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki            }
74ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki        }
75ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki        return this;
76ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki    }
77ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
78ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki    /**
79ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki     * Return a new map containing the filename-value pairs.
80ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki     */
81ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki    public ArrayMap<String, String> toSysFileMap() {
82ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki        final ArrayMap<String, String> map = new ArrayMap<>();
83ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki        addToSysFileMap(map);
84ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki        return map;
85ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki    }
86ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
87ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki    /**
88ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki     * Add the filename-value pairs to an existing map.
89ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki     */
90ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki    public void addToSysFileMap(Map<String, String> map) {
91ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki        synchronized (mLock) {
92ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki            final int size = mCoreAndFrequencies.size();
93ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
94ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki            for (int i = 0; i < size; i++) {
95ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki                final int core = mCoreAndFrequencies.keyAt(i);
96ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki                final long freq = mCoreAndFrequencies.valueAt(i);
97ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
98ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki                final String file = "/sys/devices/system/cpu/cpu" + Integer.toString(core) +
99ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki                        "/cpufreq/scaling_max_freq";
100ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki
101ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki                map.put(file, Long.toString(freq));
102ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki            }
103ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki        }
104ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki    }
105ce643a309e8d414395ec36188523d10eb64d6618Makoto Onuki}
106