Add apis to get CPU Core Info.

Change-Id: I1b95ec6dfb60e33824f78f8263baf99cd50ee1d2
diff --git a/cpu-core-info/Android.bp b/cpu-core-info/Android.bp
new file mode 100644
index 0000000..d6e12d1
--- /dev/null
+++ b/cpu-core-info/Android.bp
@@ -0,0 +1,15 @@
+cc_library_shared {
+    name: "libcpu_core_info",
+    srcs: ["cpu_core_info.cpp"],
+    vendor: true,
+    export_include_dirs: ["."],
+    shared_libs: [
+        "libcutils",
+        "libutils",
+        "liblog",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/cpu-core-info/cpu_core_info.cpp b/cpu-core-info/cpu_core_info.cpp
new file mode 100644
index 0000000..0a1c34e
--- /dev/null
+++ b/cpu-core-info/cpu_core_info.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+ *
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+#include <string>
+#include <map>
+#include <fstream>
+#include <utils/Log.h>
+#include "cpu_core_info.h"
+using namespace std;
+
+#define CPU_INFO_PATH "proc/device-tree/cpus/"
+#define MAX_CORES 16
+#define ERR_CODE -1
+
+int fetched_cpu_info;
+int number_of_cores, number_of_clusters;
+int is_defective[MAX_CORES];
+int core_cluster_map[MAX_CORES];
+map<int,vector<int>> cluster_core_map;
+
+int init() {
+    if (fetched_cpu_info == 0) {
+        if (get_cpu_info()) {
+            return ERR_CODE;
+        }
+        fetched_cpu_info = 1;
+    }
+    return 0;
+}
+
+int get_number_of_clusters() {
+    if(init()) {
+        return ERR_CODE;
+    }
+    return number_of_clusters;
+}
+
+int get_defective_cores(int *defective_cores) {
+    if(init()) {
+        return ERR_CODE;
+    }
+    int count = 0;
+    for(int i = 0; i < number_of_cores; i++) {
+        if (is_defective[i]) {
+            defective_cores[count] = i;
+            count++;
+        }
+    }
+    return count;
+}
+
+int is_core_defective(int core) {
+    if(init()) {
+        return ERR_CODE;
+    }
+    if (core < 0 || core > number_of_cores - 1) {
+        ALOGE("Core %d does not exist", core);
+        return ERR_CODE;
+    }
+    return is_defective[core];
+}
+
+int get_defective_cores_within_cluster(int cluster, int *defective_cores) {
+    if(init()) {
+        return ERR_CODE;
+    }
+    int count = 0;
+    vector<int> cores_within_cluster;
+    if( cluster_core_map.find(cluster) != cluster_core_map.end() ) {
+        cores_within_cluster = cluster_core_map[cluster];
+    } else {
+        ALOGI("Cluster %d not found", cluster);
+        return ERR_CODE;
+    }
+    for(int i = 0; i < cores_within_cluster.size(); i++) {
+        int core = cores_within_cluster.at(i);
+        if (is_defective[core]) {
+            defective_cores[count] = core;
+            count++;
+        }
+    }
+    return count;
+}
+
+int get_cluster(int core) {
+    if(init()) {
+        return ERR_CODE;
+    }
+    if (core < 0 || core > number_of_cores - 1) {
+        ALOGE("Core %d does not exist", core);
+        return ERR_CODE;
+    }
+    return core_cluster_map[core];
+}
+
+int get_cores(int *cores) {
+    if(init()) {
+        return ERR_CODE;
+    }
+    int i;
+    for (i = 0; i < number_of_cores; i++) {
+        cores[i] = i;
+    }
+    return number_of_cores;
+}
+
+int get_cores_within_cluster(int cluster, int *cores) {
+    if(init()) {
+        return ERR_CODE;
+    }
+    vector<int> cores_within_cluster;
+    if( cluster_core_map.find(cluster) != cluster_core_map.end() ) {
+        cores_within_cluster = cluster_core_map[cluster];
+    } else {
+        ALOGI("Cluster %d not found", cluster);
+        return ERR_CODE;
+    }
+    int i;
+    for(i = 0; i < cores_within_cluster.size(); i++) {
+        cores[i] = cores_within_cluster.at(i);
+    }
+    return i;
+}
+
+int get_cpu_info(){
+    string cpu_cluster_map_path(CPU_INFO_PATH);
+    cpu_cluster_map_path.append("cpu-map/");
+    DIR *cpus = opendir(CPU_INFO_PATH), *cpu_map= opendir(cpu_cluster_map_path.c_str());
+    struct dirent *cpus_entry, *cpu_map_entry, *cpu_cluster_entry;
+    fstream fin;
+    string line;
+    if (cpus == NULL) {
+        ALOGE("Could not open directory: %s" CPU_INFO_PATH);
+        return ERR_CODE;
+    } else {
+        int core = 0;
+        while((cpus_entry = readdir(cpus))) {
+            string filename = cpus_entry -> d_name;
+            if (filename.rfind("cpu@") == 0) {
+                number_of_cores++;
+                int core = filename.at(filename.find('@')+1) - '0';
+                string s(CPU_INFO_PATH);
+                s.append(filename).append("/enable-method");
+                fin.open(s, ios::in);
+                if(!fin) {
+                    ALOGE("File not found");
+                    return ERR_CODE;
+                }
+                while(getline(fin, line)) {
+                    if(line.substr(0,4) == "none") {
+                        is_defective[core] = 1;
+                    }
+                }
+                fin.close();
+            }
+            if (filename.compare("cpu-map") == 0) {
+                vector<string> cluster_dname;
+                if (cpu_map == NULL) {
+                    ALOGE("Could not open directory: %s", cpu_cluster_map_path.c_str());
+                    return ERR_CODE;
+                } else {
+                    while((cpu_map_entry = readdir(cpu_map))) {
+                        string dir_name = cpu_map_entry -> d_name;
+                        if (dir_name.rfind("cluster") == 0) {
+                            number_of_clusters++;
+                            cluster_dname.push_back(dir_name);
+                        }
+                    }
+                    sort(cluster_dname.begin(), cluster_dname.end());
+                    for(string dir_name : cluster_dname) {
+                        int cluster = dir_name.back() - '0';
+                        string s(cpu_cluster_map_path);
+                        s.append(dir_name);
+                        DIR *cpu_cluster_map = opendir(s.c_str());
+                        if (cpu_cluster_map == NULL) {
+                            ALOGE("Could not open directory: %s", s.c_str());
+                            return ERR_CODE;
+                        } else {
+                            while((cpu_cluster_entry = readdir(cpu_cluster_map))) {
+                                string cluster_dir_name = cpu_cluster_entry -> d_name;
+                                if (cluster_dir_name.rfind("core") == 0) {
+                                    core_cluster_map[core] = cluster;
+                                    core++;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (core != number_of_cores) {
+            ALOGE("Inconsistent entries detected");
+            return ERR_CODE;
+        }
+    }
+    for(int i = 0; i < number_of_cores; i++) {
+        cluster_core_map[core_cluster_map[i]].push_back(i);
+    }
+    return 0;
+}
diff --git a/cpu-core-info/cpu_core_info.h b/cpu-core-info/cpu_core_info.h
new file mode 100644
index 0000000..0fecda3
--- /dev/null
+++ b/cpu-core-info/cpu_core_info.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+ *
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <dirent.h>
+#include <vector>
+using namespace std;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//fetch all info related to cpu cores
+int get_cpu_info();
+
+//return total number of clusters
+int get_number_of_clusters();
+
+//return number and list of cores that are defective across clusters
+int get_defective_cores(int *defective_cores);
+
+//returns true if a core is defective; otherwise false
+int is_core_defective(int core);
+
+// return number and list of cores that are defective within given cluster
+int get_defective_cores_within_cluster(int cluster, int *defective_cores);
+
+//return cluster number to which the core belongs
+int get_cluster(int core);
+
+//return all the cores available
+int get_cores(int *cores);
+
+//return the cores available within given cluster
+int get_cores_within_cluster(int cluster, int *cores);
+
+#ifdef __cplusplus
+}
+#endif