marlin: add health@2.0 HAL and cycle count backup/restore
- Implement android.hardware.health@2.0-service for marlin
- Support battery cycle count backup/restore to persist partition
- Cycle count bins can now be read and set as a all, fix sepolicies
accordingly
Tests:
- pts-tradefed run pts -a arm64-v8a -m PtsHardwareInfoHostTestCases
- adb bugreport
- no "avc: denied" on health vendor service
Bug: 72776338
Bug: 72769405
Change-Id: I8052eb00fbe41aebd1e691d973e9aca32b0da125
diff --git a/CleanSpec.mk b/CleanSpec.mk
index a9caff8..796cb53 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -100,3 +100,7 @@
# Remove Widevine HAL 1.0
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.drm@1.0-service.widevine.rc)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.drm@1.0-service.widevine)
+
+# Health HAL 2.0
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.health@2.0-service)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.health@2.0-service.rc)
diff --git a/device-common.mk b/device-common.mk
index c123e6d..f495afe 100644
--- a/device-common.mk
+++ b/device-common.mk
@@ -626,3 +626,7 @@
# Enable Perfetto traced
PRODUCT_PROPERTY_OVERRIDES += \
persist.traced.enable=1
+
+# health HAL
+PRODUCT_PACKAGES += \
+ android.hardware.health@2.0-service.marlin
diff --git a/dumpstate/DumpstateDevice.cpp b/dumpstate/DumpstateDevice.cpp
index 4f56c2b..d32801e 100755
--- a/dumpstate/DumpstateDevice.cpp
+++ b/dumpstate/DumpstateDevice.cpp
@@ -161,7 +161,7 @@
DumpFileToFd(fd, "FUSB302 logs", "/d/ipc_logging/fusb302/log");
RunCommandToFd(fd, "Power supply properties", {"/vendor/bin/sh", "-c", "for f in /sys/class/power_supply/*/uevent ; do echo \"\n------ $f\" ; cat $f ; done"});
- RunCommandToFd(fd, "Battery cycle count", {"/vendor/bin/sh", "-c", "for f in 1 2 3 4 5 6 7 8 ; do echo $f > /sys/class/power_supply/bms/cycle_count_id; count=`cat /sys/class/power_supply/bms/cycle_count`; echo \"$f: $count\"; done"});
+ DumpFileToFd(fd, "Battery cycle count", "/sys/class/power_supply/bms/device/cycle_counts_bins");
RunCommandToFd(fd, "QCOM FG SRAM", {"/vendor/bin/sh", "-c", "echo 0x400 > /d/fg_memif/address ; echo 0x200 > /d/fg_memif/count ; cat /d/fg_memif/data"});
/* Check if qsee_logger tool exists */
diff --git a/health/Android.bp b/health/Android.bp
new file mode 100644
index 0000000..1d2bc5a
--- /dev/null
+++ b/health/Android.bp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+cc_binary {
+ name: "android.hardware.health@2.0-service.marlin",
+ init_rc: ["android.hardware.health@2.0-service.marlin.rc"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: [
+ "HealthService.cpp",
+ "CycleCountBackupRestore.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ static_libs: [
+ "android.hardware.health@2.0-impl",
+ "android.hardware.health@1.0-convert",
+ "libhealthservice",
+ "libbatterymonitor",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.health@2.0",
+ ],
+
+ header_libs: ["libhealthd_headers"],
+}
diff --git a/health/CycleCountBackupRestore.cpp b/health/CycleCountBackupRestore.cpp
new file mode 100644
index 0000000..581dfed
--- /dev/null
+++ b/health/CycleCountBackupRestore.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CycleCountBackupRestore.h"
+
+namespace device {
+namespace google {
+namespace marlin {
+namespace health {
+
+static constexpr char kCycCntFile[] = "sys/class/power_supply/bms/device/cycle_counts_bins";
+static constexpr char kSysPersistFile[] = "/persist/battery/qcom_cycle_counts_bins";
+static constexpr int kBuffSize = 256;
+
+CycleCountBackupRestore::CycleCountBackupRestore() { }
+
+void CycleCountBackupRestore::Restore()
+{
+ ReadFromStorage();
+ ReadFromSRAM();
+ UpdateAndSave();
+}
+
+void CycleCountBackupRestore::Backup()
+{
+ ReadFromSRAM();
+ UpdateAndSave();
+}
+
+void CycleCountBackupRestore::ReadFromStorage()
+{
+ std::string buffer;
+
+ if (!android::base::ReadFileToString(std::string(kSysPersistFile), &buffer)) {
+ LOG(ERROR) << "Cannot read the storage file";
+ return;
+ }
+
+ if (sscanf(buffer.c_str(), "%d %d %d %d %d %d %d %d",
+ &sw_bins_[0], &sw_bins_[1], &sw_bins_[2], &sw_bins_[3],
+ &sw_bins_[4], &sw_bins_[5], &sw_bins_[6], &sw_bins_[7])
+ != kBucketCount)
+ LOG(ERROR) << "data format is wrong in the storage file: " << buffer;
+ else
+ LOG(INFO) << "Storage data: " << buffer;
+}
+
+void CycleCountBackupRestore::SaveToStorage()
+{
+ char strData[kBuffSize];
+
+ snprintf(strData, kBuffSize, "%d %d %d %d %d %d %d %d",
+ sw_bins_[0], sw_bins_[1], sw_bins_[2], sw_bins_[3],
+ sw_bins_[4], sw_bins_[5], sw_bins_[6], sw_bins_[7]);
+
+ LOG(INFO) << "Save to Storage: " << strData;
+
+ if (!android::base::WriteStringToFile(strData, std::string(kSysPersistFile)))
+ LOG(ERROR) << "Write file error: " << strerror(errno);
+}
+
+void CycleCountBackupRestore::ReadFromSRAM()
+{
+ std::string buffer;
+
+ if (!android::base::ReadFileToString(std::string(kCycCntFile), &buffer)) {
+ LOG(ERROR) << "Read cycle counter error: " << strerror(errno);
+ return;
+ }
+
+ buffer = android::base::Trim(buffer);
+
+ if (sscanf(buffer.c_str(), "%d %d %d %d %d %d %d %d",
+ &hw_bins_[0], &hw_bins_[1], &hw_bins_[2], &hw_bins_[3],
+ &hw_bins_[4], &hw_bins_[5], &hw_bins_[6], &hw_bins_[7])
+ != kBucketCount)
+ LOG(ERROR) << "Failed to parse SRAM bins: " << buffer;
+ else
+ LOG(INFO) << "SRAM data: " << buffer;
+}
+
+void CycleCountBackupRestore::SaveToSRAM()
+{
+ char strData[kBuffSize];
+
+ snprintf(strData, kBuffSize, "%d %d %d %d %d %d %d %d",
+ hw_bins_[0], hw_bins_[1], hw_bins_[2], hw_bins_[3],
+ hw_bins_[4], hw_bins_[5], hw_bins_[6], hw_bins_[7]);
+
+ LOG(INFO) << "Save to SRAM: " << strData ;
+
+ if (!android::base::WriteStringToFile(strData, std::string(kCycCntFile)))
+ LOG(ERROR) << "Write data error: " << strerror(errno);
+}
+
+
+void CycleCountBackupRestore::UpdateAndSave()
+{
+ bool backup = false;
+ bool restore = false;
+ for (int i = 0; i < kBucketCount; i++) {
+ if (hw_bins_[i] < sw_bins_[i]) {
+ hw_bins_[i] = sw_bins_[i];
+ restore = true;
+ } else if (hw_bins_[i] > sw_bins_[i]) {
+ sw_bins_[i] = hw_bins_[i];
+ backup = true;
+ }
+ }
+ if (restore)
+ SaveToSRAM();
+ if (backup)
+ SaveToStorage();
+}
+
+} // namespace health
+} // namespace marlin
+} // namespace google
+} // namespace device
diff --git a/health/CycleCountBackupRestore.h b/health/CycleCountBackupRestore.h
new file mode 100644
index 0000000..6e3628d
--- /dev/null
+++ b/health/CycleCountBackupRestore.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DEVICE_GOOGLE_MARLIN_HEALTH_CYCLECOUNTBACKUPRESTORE_H
+#define DEVICE_GOOGLE_MARLIN_HEALTH_CYCLECOUNTBACKUPRESTORE_H
+
+#include <string>
+#include <android-base/file.h>
+#include <android-base/strings.h>
+#include <android-base/logging.h>
+
+namespace device {
+namespace google {
+namespace marlin {
+namespace health {
+
+static constexpr int kBucketCount = 8;
+
+class CycleCountBackupRestore {
+public:
+ CycleCountBackupRestore();
+ void Restore();
+ void Backup();
+
+private:
+ int sw_bins_[kBucketCount];
+ int hw_bins_[kBucketCount];
+
+ void ReadFromStorage();
+ void SaveToStorage();
+ void ReadFromSRAM();
+ void SaveToSRAM();
+ void UpdateAndSave();
+};
+
+} // namespace health
+} // namespace marlin
+} // namespace google
+} // namespace device
+
+#endif // #ifndef DEVICE_GOOGLE_MARLIN_HEALTH_CYCLECOUNTBACKUPRESTORE_H
diff --git a/health/HealthService.cpp b/health/HealthService.cpp
new file mode 100644
index 0000000..93f159e
--- /dev/null
+++ b/health/HealthService.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "android.hardware.health@2.0-service.marlin"
+#include <android-base/logging.h>
+
+#include <healthd/healthd.h>
+#include <health2/Health.h>
+#include <health2/service.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <android-base/file.h>
+#include <android-base/strings.h>
+
+#include <vector>
+#include <string>
+
+#include <sys/stat.h>
+
+#include "CycleCountBackupRestore.h"
+
+using android::hardware::health::V2_0::StorageInfo;
+using android::hardware::health::V2_0::DiskStats;
+using ::device::google::marlin::health::CycleCountBackupRestore;
+
+static constexpr int kBackupTrigger = 20;
+static constexpr size_t kDiskStatsSize = 11;
+static constexpr char kUFSHealthFile[] = "/sys/devices/soc/624000.ufshc/health";
+static constexpr char kUFSHealthVersionFile[] = "/sys/kernel/debug/ufshcd0/show_hba";
+static constexpr char kUFSName[] = "UFS0";
+static constexpr char kDiskStatsFile[] = "/sys/block/sda/stat";
+
+static CycleCountBackupRestore ccBackupRestore;
+
+int cycle_count_backup(int battery_level)
+{
+ static int saved_soc = 0;
+ static int soc_inc = 0;
+ static bool is_first = true;
+
+ if (is_first) {
+ is_first = false;
+ saved_soc = battery_level;
+ return 0;
+ }
+
+ if (battery_level > saved_soc) {
+ soc_inc += battery_level - saved_soc;
+ }
+
+ saved_soc = battery_level;
+
+ if (soc_inc >= kBackupTrigger) {
+ ccBackupRestore.Backup();
+ soc_inc = 0;
+ }
+ return 0;
+}
+
+// See : hardware/interfaces/health/2.0/README
+
+void healthd_board_init(struct healthd_config*)
+{
+ ccBackupRestore.Restore();
+}
+
+int healthd_board_battery_update(struct android::BatteryProperties *props)
+{
+ return cycle_count_backup(props->batteryLevel);
+}
+
+void get_storage_info(std::vector<StorageInfo>& vec_storage_info) {
+ StorageInfo storage_info = {};
+ std::string buffer, version;
+
+ storage_info.attr.isInternal = true;
+ storage_info.attr.isBootDevice = true;
+ storage_info.attr.name = std::string(kUFSName);
+
+ if (!android::base::ReadFileToString(std::string(kUFSHealthVersionFile), &version)) {
+ return;
+ }
+
+ std::vector<std::string> lines = android::base::Split(version, "\n");
+ if (lines.empty()) {
+ return;
+ }
+
+ char rev[8];
+ if (sscanf(lines[6].c_str(), "ufs version: 0x%7s\n", rev) < 1) {
+ return;
+ }
+
+ storage_info.version = "ufs " + std::string(rev);
+
+ if (!android::base::ReadFileToString(std::string(kUFSHealthFile), &buffer)) {
+ return;
+ }
+
+ lines = android::base::Split(buffer, "\n");
+ if (lines.empty()) {
+ return;
+ }
+
+ for (const auto& line : lines) {
+ char token[32];
+ uint16_t val;
+ int ret;
+ if ((ret = sscanf(line.c_str(),
+ "Health Descriptor[Byte offset 0x%*d]: %31s = 0x%hx",
+ token, &val)) < 2) {
+ continue;
+ }
+
+ if (std::string(token) == "bPreEOLInfo") {
+ storage_info.eol = val;
+ } else if (std::string(token) == "bDeviceLifeTimeEstA") {
+ storage_info.lifetimeA = val;
+ } else if (std::string(token) == "bDeviceLifeTimeEstB") {
+ storage_info.lifetimeB = val;
+ }
+ }
+
+ vec_storage_info.resize(1);
+ vec_storage_info[0] = storage_info;
+ return;
+}
+
+
+void get_disk_stats(std::vector<DiskStats>& vec_stats) {
+ DiskStats stats = {};
+
+ stats.attr.isInternal = true;
+ stats.attr.isBootDevice = true;
+ stats.attr.name = std::string(kUFSName);
+
+ std::string buffer;
+ if (!android::base::ReadFileToString(std::string(kDiskStatsFile), &buffer)) {
+ LOG(ERROR) << kDiskStatsFile << ": ReadFileToString failed.";
+ return;
+ }
+
+ // Regular diskstats entries
+ std::stringstream ss(buffer);
+ for (uint i = 0; i < kDiskStatsSize; i++) {
+ ss >> *(reinterpret_cast<uint64_t*>(&stats) + i);
+ }
+ vec_stats.resize(1);
+ vec_stats[0] = stats;
+
+ return;
+}
+
+int main(void) {
+ return health_service_main();
+}
diff --git a/health/android.hardware.health@2.0-service.marlin.rc b/health/android.hardware.health@2.0-service.marlin.rc
new file mode 100644
index 0000000..398a24e
--- /dev/null
+++ b/health/android.hardware.health@2.0-service.marlin.rc
@@ -0,0 +1,4 @@
+service vendor.health-hal-2-0 /vendor/bin/hw/android.hardware.health@2.0-service.marlin
+ class hal
+ user system
+ group system
diff --git a/init.common.rc b/init.common.rc
index 7285b8f..dce7d46 100644
--- a/init.common.rc
+++ b/init.common.rc
@@ -114,6 +114,9 @@
restorecon_recursive /persist
mkdir /persist/data 0700 system system
+ # for android.hardware.health@2.0-service.marlin cycle count backup
+ mkdir /persist/battery 0700 system system
+
# Start HW service manager early
start hwservicemanager
@@ -369,6 +372,11 @@
# wait for devices
wait_for_prop sys.qcom.devup 1
+ # vendor.health-hal needs to be able to RW
+ chown system system /sys/devices/soc/qpnp-fg-17/cycle_counts_bins
+ # HardwareInfo needs to be able to read CC bins
+ chmod 644 /sys/devices/soc/qpnp-fg-17/cycle_counts_bins
+
on boot
# from init.power.sh
# disable thermal hotplug to switch governor
@@ -525,9 +533,6 @@
chown system system /d/fg_memif/count
chown system system /d/fg_memif/address
- # com.google.android.hardwareinfo needs to be able to read cycle counts
- chmod 0666 /sys/class/power_supply/bms/cycle_count_id
-
on property:wc_transport.start_hci=true
start vendor.start_hci_filter
@@ -808,7 +813,7 @@
# UFS health
chmod 755 /sys/kernel/debug/ufshcd0
- chown 644 /sys/kernel/debug/ufshcd0/err_state
+ chmod 644 /sys/kernel/debug/ufshcd0/err_state
chmod 644 /sys/kernel/debug/ufshcd0/power_mode
chmod 644 /sys/kernel/debug/ufshcd0/host_regs
chmod 644 /sys/kernel/debug/ufshcd0/show_hba
diff --git a/manifest.xml b/manifest.xml
index 3f3863e..72c5c95 100644
--- a/manifest.xml
+++ b/manifest.xml
@@ -150,6 +150,15 @@
<name>IComposer</name>
<instance>default</instance>
</interface>
+ </hal>
+ <hal format="hidl">
+ <name>android.hardware.health</name>
+ <transport>hwbinder</transport>
+ <version>2.0</version>
+ <interface>
+ <name>IHealth</name>
+ <instance>default</instance>
+ </interface>
</hal>
<hal format="hidl">
<name>android.hardware.keymaster</name>
diff --git a/sepolicy/file.te b/sepolicy/file.te
index ec2c14c..7945611 100644
--- a/sepolicy/file.te
+++ b/sepolicy/file.te
@@ -74,6 +74,7 @@
type persist_file, file_type;
type persist_data_file, file_type;
type persist_display_file, file_type;
+type persist_battery_file, file_type;
# msm_irqbalance
type proc_irq, fs_type;
diff --git a/sepolicy/file_contexts b/sepolicy/file_contexts
index 437e07f..259d510 100644
--- a/sepolicy/file_contexts
+++ b/sepolicy/file_contexts
@@ -131,6 +131,8 @@
/vendor/bin/init\.radio\.sh u:object_r:init_radio_exec:s0
/vendor/bin/init\.foreground\.sh u:object_r:init_foreground_exec:s0
+/vendor/bin/hw/android\.hardware\.health@2\.0-service\.marlin u:object_r:hal_health_default_exec:s0
+
###############################################
# same-process HAL files and their dependencies
#
@@ -202,6 +204,7 @@
/persist(/.*)? u:object_r:persist_file:s0
/persist/data(/.*)? u:object_r:persist_data_file:s0
/persist/display(/.*)? u:object_r:persist_display_file:s0
+/persist/battery(/.*)? u:object_r:persist_battery_file:s0
/persist/sensorcal\.json u:object_r:sensors_cal_file:s0
# hidraw dynamic sensor
diff --git a/sepolicy/genfs_contexts b/sepolicy/genfs_contexts
index 65f3a65..33ea628 100644
--- a/sepolicy/genfs_contexts
+++ b/sepolicy/genfs_contexts
@@ -56,7 +56,7 @@
genfscon sysfs /devices/soc/75b5000.i2c/i2c-7/7-001d/power_supply u:object_r:sysfs_batteryinfo:s0
genfscon sysfs /devices/soc/msm-bcl-14/power_supply u:object_r:sysfs_batteryinfo:s0
genfscon sysfs /devices/soc/soc:qcom,bcl/power_supply u:object_r:sysfs_batteryinfo:s0
-genfscon sysfs /devices/soc/qpnp-fg-17/power_supply u:object_r:sysfs_batteryinfo:s0
+genfscon sysfs /devices/soc/qpnp-fg-17 u:object_r:sysfs_batteryinfo:s0
genfscon sysfs /devices/soc/qpnp-smbcharger-16/power_supply u:object_r:sysfs_batteryinfo:s0
genfscon sysfs /devices/virtual/timed_output/vibrator/voltage_level u:object_r:sysfs_vibrator:s0
genfscon sysfs /module/diagchar/parameters/timestamp_switch u:object_r:sysfs_timestamp_switch:s0
diff --git a/sepolicy/hal_dumpstate_impl.te b/sepolicy/hal_dumpstate_impl.te
index 90558fa..d7c1d35 100644
--- a/sepolicy/hal_dumpstate_impl.te
+++ b/sepolicy/hal_dumpstate_impl.te
@@ -66,7 +66,7 @@
# Query and dump power supply nodes
allow hal_dumpstate_impl sysfs_batteryinfo:dir search;
-allow hal_dumpstate_impl sysfs_batteryinfo:file rw_file_perms;
+allow hal_dumpstate_impl sysfs_batteryinfo:file r_file_perms;
# Dump QCOM FG content
allow hal_dumpstate_impl debugfs_fg_sram:dir search;
diff --git a/sepolicy/hal_health_default.te b/sepolicy/hal_health_default.te
new file mode 100644
index 0000000..a5f39de
--- /dev/null
+++ b/sepolicy/hal_health_default.te
@@ -0,0 +1,13 @@
+r_dir_file(hal_health_default, sysfs_msm_subsys)
+
+allow hal_health_default debugfs_ufs:dir search;
+allow hal_health_default sysfs_scsi_devices_0000:dir search;
+allow hal_health_default debugfs_ufs:file { getattr open read };
+allow hal_health_default sysfs_scsi_devices_0000:file { getattr open read };
+
+allow hal_health_default persist_battery_file:file create_file_perms;
+allow hal_health_default persist_battery_file:dir rw_dir_perms;
+allow hal_health_default persist_file:dir search;
+allow hal_health_default kmsg_device:chr_file { open write };
+allow hal_health_default sysfs_msm_subsys:file { write };
+allow hal_health_default sysfs_batteryinfo:file rw_file_perms;
diff --git a/sepolicy/hardware_info_app.te b/sepolicy/hardware_info_app.te
index a25be67..23d0ddd 100644
--- a/sepolicy/hardware_info_app.te
+++ b/sepolicy/hardware_info_app.te
@@ -7,7 +7,7 @@
# SysFS
allow hardware_info_app sysfs_batteryinfo:dir search;
-allow hardware_info_app sysfs_batteryinfo:file { getattr open read write };
+allow hardware_info_app sysfs_batteryinfo:file { getattr open read };
allow hardware_info_app sysfs_camera:dir search;
allow hardware_info_app sysfs_camera:file { getattr open read };
allow hardware_info_app sysfs_msm_subsys:dir search;