QSPA AIDL hal implementation
Change-Id: I5f486ab2ac9bb088274beec44bb963e962ad0827
diff --git a/qspaservice/Android.bp b/qspaservice/Android.bp
new file mode 100644
index 0000000..42af180
--- /dev/null
+++ b/qspaservice/Android.bp
@@ -0,0 +1,17 @@
+cc_binary{
+ name: "vendor.qti.qspa-service",
+ init_rc: ["vendor.qti.qspa-service.rc"],
+ srcs:[
+ "src/main.cpp",
+ "src/Qspa.cpp"
+ ],
+ vendor:true,
+ vintf_fragments: ["vendor.qti.qspa-service.xml"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libbinder_ndk",
+ "vendor.qti.hardware.qspa-V1-ndk",
+ ],
+}
diff --git a/qspaservice/src/Qspa.cpp b/qspaservice/src/Qspa.cpp
new file mode 100644
index 0000000..919bc03
--- /dev/null
+++ b/qspaservice/src/Qspa.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+*/
+
+#include "Qspa.h"
+#include <fstream>
+#include <regex>
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <algorithm>
+
+using namespace std;
+
+namespace aidl {
+namespace vendor {
+namespace qti {
+namespace hardware {
+namespace qspa {
+
+ndk::ScopedAStatus Qspa::get_all_subparts(std::vector<PartInfo>* _aidl_return) {
+ ALOGI("Request received for api: get_all_subparts");
+ vector<PartInfo> partinfo_return;
+ for (int i = 0; i < defective_parts.size(); i++) {
+ string subpart_path(PART_INFO_PATH);
+ subpart_path.append(defective_parts[i]);
+ fstream fin;
+ fin.open(subpart_path, ios::in);
+ string line;
+ if (!fin) {
+ ALOGE("No device path found for Subpart- %s", defective_parts[i].c_str());
+ continue;
+ }
+ if (!getline(fin, line)) {
+ ALOGE("Unable to read file: %s", subpart_path.c_str());
+ return ndk::ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
+ }
+ ALOGI("part is: %s", defective_parts[i].c_str());
+ stringstream data(line);
+ string intermediate;
+ std::vector<int32_t> tokens;
+ PartInfo partinfo;
+ partinfo.part = defective_parts[i];
+ // Tokenizing w.r.t ','
+ while (getline(data, intermediate, ',')) {
+ ALOGI("data is %s", intermediate.c_str());
+ tokens.push_back(stoi(intermediate,0,16));
+ }
+ partinfo.subpart_data = tokens;
+ partinfo_return.push_back(partinfo);
+ }
+ *_aidl_return = partinfo_return;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Qspa::get_available_parts(std::vector<std::string>* _aidl_return) {
+ ALOGI("Request received for api: get_available_parts");
+ vector<std::string> parts;
+ for (int i = 0; i < defective_parts.size(); i++) {
+ string subpart_path(PART_INFO_PATH);
+ subpart_path.append(defective_parts[i]);
+ fstream fin;
+ fin.open(subpart_path, ios::in);
+ string line;
+ if (!fin) {
+ ALOGE("No device path found for Subpart- %s", defective_parts[i].c_str());
+ continue;
+ }
+ if (!getline(fin, line)) {
+ ALOGE("Unable to read file: %s", subpart_path.c_str());
+ return ndk::ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
+ }
+ ALOGI("part is: %s", defective_parts[i].c_str());
+ parts.push_back(defective_parts[i].c_str());
+ }
+ *_aidl_return = parts;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Qspa::get_subpart_info(const std::string& in_part,
+ std::vector<int32_t>* _aidl_return) {
+ ALOGI("Request received for api: get_subpart_info(%s)", in_part.c_str());
+ string subpart_path(PART_INFO_PATH);
+ subpart_path.append(in_part);
+ fstream fin;
+ fin.open(subpart_path, ios::in);
+ string line;
+ if (!fin || !getline(fin, line)) {
+ ALOGE("Unable to open or read file: %s", subpart_path.c_str());
+ return ndk::ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
+ }
+ stringstream data(line);
+ string intermediate;
+ std::vector<int32_t> tokens;
+ // Tokenizing w.r.t ','
+ while (getline(data, intermediate, ',')) {
+ ALOGI("data is %s", intermediate.c_str());
+ tokens.push_back(stoi(intermediate,0,16));
+ }
+ *_aidl_return = tokens;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Qspa::get_num_available_cpus(int32_t* _aidl_return) {
+ ALOGI("Request received for api: get_num_available_cpus");
+ fstream fin;
+ fin.open(CPU_INFO_PATH, ios::in);
+ string line;
+ if (!fin || !getline(fin, line)) {
+ ALOGE("Unable to open or read file: %s", CPU_INFO_PATH);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
+ }
+ ALOGI("cpus Range: %s",line.c_str());
+ int32_t cpu = 0;
+ cpu = stoi(std::regex_replace(line, std::regex("0-"), ""));
+ ALOGI("Number of cpus: %d",cpu+1);
+ *_aidl_return = cpu+1;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Qspa::get_num_available_clusters(int32_t* _aidl_return) {
+ ALOGI("Request received for api: get_num_available_clusters");
+ DIR *clusters_dir = opendir(CLUSTER_INFO_PATH);
+ struct dirent *clusters_entry;
+ if (clusters_dir == NULL) {
+ ALOGE("Could not open directory: %s", CLUSTER_INFO_PATH);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
+ }
+ int32_t clusters = 0;
+ while ((clusters_entry = readdir(clusters_dir))) {
+ string policyname = clusters_entry -> d_name;
+ regex str_expr ("policy[0-9]*");
+ if (std::regex_match(policyname.begin(), policyname.end(), str_expr)) {
+ ALOGI("policyname is %s",policyname.c_str());
+ clusters++;
+ }
+ }
+ ALOGI("Number of clusters: %d",clusters);
+ *_aidl_return = clusters;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Qspa::get_num_physical_clusters(int32_t* _aidl_return) {
+ ALOGI("Request received for api: get_num_physical_clusters");
+ DIR *clusters_dir = opendir(PHYCLUSTER_INFO_PATH);
+ struct dirent *clusters_entry;
+ if (clusters_dir == NULL) {
+ ALOGE("Could not open directory: %s", PHYCLUSTER_INFO_PATH);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
+ }
+ int32_t clusters = 0;
+ while ((clusters_entry = readdir(clusters_dir))) {
+ string dir_name = clusters_entry -> d_name;
+ if (dir_name.rfind("cluster") == 0) {
+ ALOGI("%s", dir_name.c_str());;
+ clusters++;
+ }
+ cout<<endl;
+ }
+ ALOGI("Number of clusters: %d",clusters);
+ *_aidl_return = clusters;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Qspa::get_cpus_of_physical_clusters(int32_t in_physical_cluster_number,
+ std::vector<int32_t>* _aidl_return) {
+ ALOGI("Request received for api: get_cpus_of_physical_clusters(%d)", in_physical_cluster_number);
+ fstream fin;
+ fin.open(CPU_INFO_PATH, ios::in);
+ string line;
+ if (!fin || !getline(fin, line)) {
+ ALOGE("Unable to open or read file: %s", CPU_INFO_PATH);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
+ }
+ ALOGI("cpus Range: %s",line.c_str());
+ int cpus = 0;
+ cpus = stoi(std::regex_replace(line, std::regex("0-"), "")) + 1;
+ ALOGI("Number of available cpus: %d", cpus);
+ int first_cpu_in_cluster = -1;
+ for (int i = 0; i < cpus; i++) {
+ string cpu_cluster_map_path = "/sys/devices/system/cpu/cpu" + to_string(i) + "/topology/";
+ struct stat sb;
+ string path1 = cpu_cluster_map_path.append("/physical_package_id");
+ string path2 = cpu_cluster_map_path.append("/cluster_id");
+ if (stat(path1.c_str(), &sb) == 0 && !(sb.st_mode & S_IFDIR)) {
+ fstream fin;
+ fin.open(path1, ios::in);
+ string cid;
+ if (!fin || !getline(fin, cid)) {
+ ALOGE("Unable to open or read file: %s", path1.c_str());
+ return ndk::ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
+ }
+ if (stoi(cid) == in_physical_cluster_number) {
+ first_cpu_in_cluster = i;
+ break;
+ }
+ }
+ else if (stat(path2.c_str(), &sb) == 0 && !(sb.st_mode & S_IFDIR)) {
+ ALOGI("cluster_id exists for cpu: %d", i);
+ fstream fin;
+ fin.open(path2, ios::in);
+ string cid;
+ if (!fin || !getline(fin, cid)) {
+ ALOGE("Unable to open or read file: %s", path2.c_str());
+ return ndk::ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
+ }
+ if (stoi(cid) == in_physical_cluster_number) {
+ first_cpu_in_cluster = i;
+ break;
+ }
+ }
+ }
+ ALOGI("First cpu in cluster is: %d", first_cpu_in_cluster);
+ std::vector<int32_t> tokens;
+ if (first_cpu_in_cluster != -1) {
+ string cpus_path(CLUSTER_INFO_PATH);
+ cpus_path.append("/policy" + to_string(first_cpu_in_cluster) + "/related_cpus");
+ fstream fi;
+ fi.open(cpus_path, ios::in);
+ string rel_cpus;
+ if (!fi || !getline(fi, rel_cpus)) {
+ ALOGE("Unable to open or read file: %s", cpus_path.c_str());
+ return ndk::ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
+ }
+ stringstream data(rel_cpus);
+ string intermediate;
+ // Tokenizing w.r.t ' '
+ while (getline(data, intermediate, ' ')) {
+ ALOGI("data is %s", intermediate.c_str());
+ tokens.push_back(stoi(intermediate,0,16));
+ }
+ }
+ else {
+ tokens.push_back(-1);
+ }
+ *_aidl_return = tokens;
+ return ndk::ScopedAStatus::ok();
+}
+
+Qspa::Qspa() {
+ ALOGI("Within Qspa constructor");
+}
+
+}
+}
+}
+}
+}
\ No newline at end of file
diff --git a/qspaservice/src/Qspa.h b/qspaservice/src/Qspa.h
new file mode 100644
index 0000000..651d97f
--- /dev/null
+++ b/qspaservice/src/Qspa.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+*/
+
+#include <aidl/vendor/qti/hardware/qspa/BnQspa.h>
+#include <vector>
+#include <log/log.h>
+#include <iostream>
+#include <android-base/properties.h>
+#include<map>
+
+#define CPU_INFO_PATH "/sys/devices/system/cpu/possible"
+#define CLUSTER_INFO_PATH "/sys/devices/system/cpu/cpufreq"
+#define PHYCLUSTER_INFO_PATH "/proc/device-tree/cpus/cpu-map"
+#define PART_INFO_PATH "/sys/devices/soc0/"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "qspa-service"
+
+using namespace std;
+using aidl::vendor::qti::hardware::qspa::PartInfo;
+namespace aidl {
+namespace vendor {
+namespace qti {
+namespace hardware {
+namespace qspa {
+
+class Qspa : public BnQspa {
+ public:
+ Qspa();
+ ndk::ScopedAStatus get_all_subparts(std::vector<PartInfo>* _aidl_return) override;
+ ndk::ScopedAStatus get_available_parts(std::vector<std::string>* _aidl_return) override;
+ ndk::ScopedAStatus get_subpart_info(const std::string& in_part,
+ std::vector<int32_t>* _aidl_return) override;
+ ndk::ScopedAStatus get_num_available_cpus(int32_t* _aidl_return) override;
+ ndk::ScopedAStatus get_num_available_clusters(int32_t* _aidl_return) override;
+ ndk::ScopedAStatus get_num_physical_clusters(int32_t* _aidl_return) override;
+ ndk::ScopedAStatus get_cpus_of_physical_clusters(int32_t in_physical_cluster_number,
+ std::vector<int32_t>* _aidl_return) override;
+ private:
+ std::vector<std::string> defective_parts = {"gpu", "video", "camera", "display", "audio",
+ "modem", "wlan", "comp", "sensors", "npu", "spss", "nav", "comp1", "display1",
+ "nsp", "eva"};
+
+};
+
+}
+}
+}
+}
+}
+
diff --git a/qspaservice/src/main.cpp b/qspaservice/src/main.cpp
new file mode 100644
index 0000000..a90becc
--- /dev/null
+++ b/qspaservice/src/main.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+*/
+
+#include "Qspa.h"
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::vendor::qti::hardware::qspa::Qspa;
+using namespace std;
+
+int main(){
+ ABinderProcess_startThreadPool();
+ std::shared_ptr<Qspa> qspa = ndk::SharedRefBase::make<Qspa>();
+ const std::string qspaName = std::string() + Qspa::descriptor + "/default";
+ if (qspa == nullptr) {
+ ALOGE("QSPA object is null, Failed to register !");
+ }
+ else {
+ if (qspa->asBinder() == nullptr) {
+ ALOGE("QSPA binder object is null!");
+ }
+ else {
+ binder_status_t status = AServiceManager_addService(qspa->asBinder().get(), qspaName.c_str());
+ CHECK_EQ(status, STATUS_OK);
+ ALOGI("QSPA service registered !");
+ ABinderProcess_joinThreadPool();
+ }
+ }
+ return EXIT_FAILURE;
+}
\ No newline at end of file
diff --git a/qspaservice/vendor.qti.qspa-service.rc b/qspaservice/vendor.qti.qspa-service.rc
new file mode 100644
index 0000000..799217f
--- /dev/null
+++ b/qspaservice/vendor.qti.qspa-service.rc
@@ -0,0 +1,7 @@
+# Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+# SPDX-License-Identifier: BSD-3-Clause-Clear
+
+service vendor.qspa-service /vendor/bin/vendor.qti.qspa-service
+ class hal
+ user system
+ group system
\ No newline at end of file
diff --git a/qspaservice/vendor.qti.qspa-service.xml b/qspaservice/vendor.qti.qspa-service.xml
new file mode 100644
index 0000000..f1939fe
--- /dev/null
+++ b/qspaservice/vendor.qti.qspa-service.xml
@@ -0,0 +1,14 @@
+<!-- Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+SPDX-License-Identifier: BSD-3-Clause-Clear
+-->
+
+<manifest version="1.0" type="device">
+ <hal format="aidl" optional="true">
+ <name>vendor.qti.hardware.qspa</name>
+ <version>1</version>
+ <interface>
+ <name>IQspa</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>