Merge changes I1148ab4e,I3e8c632d,I786d7281,Icbd87b35

* changes:
  libtimeinstate: export cputimeinstate.h
  libtimeinstate: add getCpuFreqs() function
  libtimeinstate: clear stale map values in startTrackingUidTimes()
  libtimeinstate: open maps write-only
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index a8f7d92..b1943a4 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -14,6 +14,7 @@
         "-Wall",
         "-Wextra",
     ],
+    export_include_dirs: ["."],
 }
 
 cc_test {
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 45fea85..037846b 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -85,6 +85,16 @@
     return policyN1 - policyN2;
 }
 
+static int bpf_obj_get_wronly(const char *pathname) {
+    union bpf_attr attr;
+
+    memset(&attr, 0, sizeof(attr));
+    attr.pathname = ptr_to_u64((void *)pathname);
+    attr.file_flags = BPF_F_WRONLY;
+
+    return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
+}
+
 static bool initGlobals() {
     std::lock_guard<std::mutex> guard(gInitializedMutex);
     if (gInitialized) return true;
@@ -153,17 +163,17 @@
 bool startTrackingUidTimes() {
     if (!initGlobals()) return false;
 
-    unique_fd fd(bpf_obj_get(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
-    if (fd < 0) return false;
+    unique_fd cpuPolicyFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
+    if (cpuPolicyFd < 0) return false;
 
     for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) {
         for (auto &cpu : gPolicyCpus[i]) {
-            if (writeToMapEntry(fd, &cpu, &i, BPF_ANY)) return false;
+            if (writeToMapEntry(cpuPolicyFd, &cpu, &i, BPF_ANY)) return false;
         }
     }
 
-    unique_fd fd2(bpf_obj_get(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
-    if (fd2 < 0) return false;
+    unique_fd freqToIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
+    if (freqToIdxFd < 0) return false;
     freq_idx_key_t key;
     for (uint32_t i = 0; i < gNPolicies; ++i) {
         key.policy = i;
@@ -173,14 +183,41 @@
             // The uid_times map still uses 0-based indexes, and the sched_switch program handles
             // conversion between them, so this does not affect our map reading code.
             uint32_t idx = j + 1;
-            if (writeToMapEntry(fd2, &key, &idx, BPF_ANY)) return false;
+            if (writeToMapEntry(freqToIdxFd, &key, &idx, BPF_ANY)) return false;
         }
     }
 
+    unique_fd cpuLastUpdateFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_last_update_map"));
+    if (cpuLastUpdateFd < 0) return false;
+    std::vector<uint64_t> zeros(get_nprocs_conf(), 0);
+    uint32_t zero = 0;
+    if (writeToMapEntry(cpuLastUpdateFd, &zero, zeros.data(), BPF_ANY)) return false;
+
+    unique_fd nrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_nr_active_map"));
+    if (nrActiveFd < 0) return false;
+    if (writeToMapEntry(nrActiveFd, &zero, &zero, BPF_ANY)) return false;
+
+    unique_fd policyNrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_nr_active_map"));
+    if (policyNrActiveFd < 0) return false;
+    for (uint32_t i = 0; i < gNPolicies; ++i) {
+        if (writeToMapEntry(policyNrActiveFd, &i, &zero, BPF_ANY)) return false;
+    }
+
+    unique_fd policyFreqIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map"));
+    if (policyFreqIdxFd < 0) return false;
+    for (uint32_t i = 0; i < gNPolicies; ++i) {
+        if (writeToMapEntry(policyFreqIdxFd, &i, &zero, BPF_ANY)) return false;
+    }
+
     return attachTracepointProgram("sched", "sched_switch") &&
             attachTracepointProgram("power", "cpu_frequency");
 }
 
+std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs() {
+    if (!gInitialized && !initGlobals()) return {};
+    return gPolicyFreqs;
+}
+
 // Retrieve the times in ns that uid spent running at each CPU frequency.
 // Return contains no value on error, otherwise it contains a vector of vectors using the format:
 // [[t0_0, t0_1, ...],
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index f620715..49469d8 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -26,6 +26,7 @@
 std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid);
 std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
     getUidsCpuFreqTimes();
+std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs();
 
 struct concurrent_time_t {
     std::vector<uint64_t> active;
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index e82aad8..23d87fd 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -367,5 +367,16 @@
     ASSERT_EQ(allConcurrentTimes->find(uid), allConcurrentTimes->end());
 }
 
+TEST(TimeInStateTest, GetCpuFreqs) {
+    auto freqs = getCpuFreqs();
+    ASSERT_TRUE(freqs.has_value());
+
+    auto times = getUidCpuFreqTimes(0);
+    ASSERT_TRUE(times.has_value());
+
+    ASSERT_EQ(freqs->size(), times->size());
+    for (size_t i = 0; i < freqs->size(); ++i) EXPECT_EQ((*freqs)[i].size(), (*times)[i].size());
+}
+
 } // namespace bpf
 } // namespace android