Implementing per-property access control

Test: unit tests provided, verified local build is not failing

Fix: b/33343558

Change-Id: I96d0160d1dde1e527eaba3982b0a48515e9bccd7
diff --git a/vehicle/2.0/default/Android.mk b/vehicle/2.0/default/Android.mk
index 46733e5..e61aaa3 100644
--- a/vehicle/2.0/default/Android.mk
+++ b/vehicle/2.0/default/Android.mk
@@ -22,6 +22,7 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(module_prefix)-manager-lib
 LOCAL_SRC_FILES := \
+    vehicle_hal_manager/AccessControlConfigParser.cpp \
     vehicle_hal_manager/SubscriptionManager.cpp \
     vehicle_hal_manager/VehicleHalManager.cpp \
 
@@ -67,6 +68,7 @@
 LOCAL_WHOLE_STATIC_LIBRARIES := $(module_prefix)-manager-lib
 
 LOCAL_SRC_FILES:= \
+    tests/AccessControlConfigParser_test.cpp \
     tests/VehicleObjectPool_test.cpp \
     tests/VehiclePropConfigIndex_test.cpp \
     tests/SubscriptionManager_test.cpp \
diff --git a/vehicle/2.0/default/tests/AccessControlConfigParser_test.cpp b/vehicle/2.0/default/tests/AccessControlConfigParser_test.cpp
new file mode 100644
index 0000000..92d7e39
--- /dev/null
+++ b/vehicle/2.0/default/tests/AccessControlConfigParser_test.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 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 <gtest/gtest.h>
+#include <memory>
+#include <fstream>
+#include <unordered_set>
+
+#include "vehicle_hal_manager/AccessControlConfigParser.h"
+
+namespace android {
+namespace hardware {
+namespace vehicle {
+namespace V2_0 {
+
+namespace {
+
+class AccessControlConfigParserTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        std::vector<VehicleProperty> supportedProperties {
+            VehicleProperty::HVAC_FAN_SPEED,
+            VehicleProperty::HVAC_FAN_DIRECTION,
+        };
+        parser.reset(new AccessControlConfigParser(supportedProperties));
+    }
+public:
+    PropertyAclMap aclMap;
+    std::unique_ptr<AccessControlConfigParser> parser;
+};
+
+TEST_F(AccessControlConfigParserTest, basicParsing) {
+    std::stringstream file;
+    file << "S:0x0500 1000 RW" << std::endl;
+
+    ASSERT_TRUE(parser->parseFromStream(&file, &aclMap));
+
+    ASSERT_EQ(1, aclMap.size());
+    auto it = aclMap.find(VehicleProperty::HVAC_FAN_SPEED);
+    ASSERT_NE(aclMap.end(), it);
+    ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, it->second.access);
+    ASSERT_EQ(VehicleProperty::HVAC_FAN_SPEED, it->second.propId);
+    ASSERT_EQ(1000u, it->second.uid);
+}
+
+TEST_F(AccessControlConfigParserTest, multipleUids) {
+    std::stringstream file;
+    file << "Set AID_AUDIO 1004" << std::endl
+            << "Set AID_SYSTEM 1000" << std::endl
+            << "S:0x0500 AID_SYSTEM RW" << std::endl
+            << "S:0x0500 AID_AUDIO RW" << std::endl
+            << "S:0x0500 0xbeef R" << std::endl;  // Read-only.
+
+    std::unordered_set<unsigned> expectedUids {1000, 1004, 0xbeef};
+
+    ASSERT_TRUE(parser->parseFromStream(&file, &aclMap));
+
+    auto range = aclMap.equal_range(VehicleProperty::HVAC_FAN_SPEED);
+    for (auto it = range.first; it != range.second; ++it) {
+        auto& acl = it->second;
+
+        ASSERT_EQ(1, expectedUids.count(acl.uid))
+                << " uid: " << std::hex << acl.uid;
+
+        if (acl.uid == 0xbeef) {
+            ASSERT_EQ(VehiclePropertyAccess::READ, acl.access);
+        } else {
+            ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, acl.access);
+        }
+    }
+}
+
+TEST_F(AccessControlConfigParserTest, fileContainsJunk) {
+    std::stringstream file;
+    file << "This string will be ignored with warning in the log" << std::endl
+         << "# However comments are quit legitimate" << std::endl
+         << "S:0x0500 0xbeef R # YAY" << std::endl;
+
+    ASSERT_FALSE(parser->parseFromStream(&file, &aclMap));
+
+    ASSERT_EQ(1, aclMap.size());
+    auto it = aclMap.find(VehicleProperty::HVAC_FAN_SPEED);
+    ASSERT_NE(aclMap.end(), it);
+    ASSERT_EQ(VehiclePropertyAccess::READ, it->second.access);
+    ASSERT_EQ(VehicleProperty::HVAC_FAN_SPEED, it->second.propId);
+    ASSERT_EQ(0xbeef, it->second.uid);
+}
+
+TEST_F(AccessControlConfigParserTest, badIntegerFormat) {
+    std::stringstream file;
+    file << "S:0x0500 A12 RW " << std::endl;
+
+    ASSERT_FALSE(parser->parseFromStream(&file, &aclMap));
+    ASSERT_EQ(0, aclMap.size());
+}
+
+TEST_F(AccessControlConfigParserTest, ignoreNotSupportedProperties) {
+    std::stringstream file;
+    file << "S:0x0666 1000 RW " << std::endl;
+
+    ASSERT_FALSE(parser->parseFromStream(&file, &aclMap));
+    ASSERT_EQ(0, aclMap.size());
+}
+
+TEST_F(AccessControlConfigParserTest, multipleCalls) {
+    std::stringstream configFile;
+    configFile << "S:0x0500 1000 RW" << std::endl;
+
+    ASSERT_TRUE(parser->parseFromStream(&configFile, &aclMap));
+    ASSERT_EQ(1, aclMap.size());
+
+    std::stringstream configFile2;
+    configFile2 << "S:0x0501 1004 RW" << std::endl;
+    ASSERT_TRUE(parser->parseFromStream(&configFile2, &aclMap));
+    ASSERT_EQ(2, aclMap.size());
+
+    auto it = aclMap.find(VehicleProperty::HVAC_FAN_SPEED);
+    ASSERT_NE(aclMap.end(), it);
+    ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, it->second.access);
+    ASSERT_EQ(VehicleProperty::HVAC_FAN_SPEED, it->second.propId);
+    ASSERT_EQ(1000u, it->second.uid);
+
+    it = aclMap.find(VehicleProperty::HVAC_FAN_DIRECTION);
+    ASSERT_NE(aclMap.end(), it);
+    ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, it->second.access);
+    ASSERT_EQ(VehicleProperty::HVAC_FAN_DIRECTION, it->second.propId);
+    ASSERT_EQ(1004u, it->second.uid);
+}
+
+
+}  // namespace anonymous
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace hardware
+}  // namespace android
diff --git a/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.cpp b/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.cpp
new file mode 100644
index 0000000..1d436c5
--- /dev/null
+++ b/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2016 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.vehicle@2.0-impl"
+#include <android/log.h>
+
+#include <fstream>
+#include <sstream>
+#include <iostream>
+
+#include "AccessControlConfigParser.h"
+
+namespace android {
+namespace hardware {
+namespace vehicle {
+namespace V2_0 {
+
+AccessControlConfigParser::AccessControlConfigParser(
+        const std::vector<VehicleProperty>& properties) {
+    // Property Id in the config file doesn't include information about
+    // type and area. So we want to create a map from these kind of
+    // *stripped* properties to the whole VehicleProperty.
+    // We also want to filter out ACL to the properties that supported
+    // by concrete Vehicle HAL implementation.
+    for (VehicleProperty vehicleProperty : properties) {
+        auto numProp = static_cast<int>(vehicleProperty);
+        numProp &= ~static_cast<int>(VehiclePropertyType::MASK)
+                & ~static_cast<int>(VehicleArea::MASK);
+        mStrippedToVehiclePropertyMap.emplace(numProp, vehicleProperty);
+    }
+}
+
+bool AccessControlConfigParser::parseFromStream(
+        std::istream* stream, PropertyAclMap* propertyAclMap) {
+    std::list<std::string> tokens;
+    std::string line;
+    int lineNo = 0;
+    bool warnings = false;
+    for (;std::getline(*stream, line); lineNo++) {
+        split(line, &tokens);
+        if (!processTokens(&tokens, propertyAclMap)) {
+            warnings = true;
+            ALOGW("Failed to parse line %d : %s", lineNo, line.c_str());
+        }
+    }
+    return !warnings;
+}
+
+
+bool AccessControlConfigParser::processTokens(std::list<std::string>* tokens,
+                                              PropertyAclMap* propertyAclMap) {
+    std::string token = readNextToken(tokens);
+    if (token.empty() || token[0] == '#') {   // Ignore comment.
+        return true;
+    }
+
+    if (token == "Set") {
+        std::string alias = readNextToken(tokens);
+        std::string strUid = readNextToken(tokens);
+        if (alias.empty() || strUid.empty()) {
+            ALOGW("Expected alias and UID must be specified");
+            return false;
+        }
+        int uid;
+        if (!parseInt(strUid.c_str(), &uid)) {
+            ALOGW("Invalid UID: %d", uid);
+        }
+        mUidMap.emplace(std::move(alias), uid);
+    } else if (token.size() > 2 && token[1] == ':') {
+        VehiclePropertyGroup propGroup;
+        if (!parsePropertyGroup(token[0], &propGroup)) {
+            return false;
+        }
+        std::string strUid = readNextToken(tokens);
+        std::string strAccess = readNextToken(tokens);
+        if (strUid.empty() || strAccess.empty()) {
+            ALOGW("Expected UID and access for property: %s",
+                  token.c_str());
+        }
+
+
+        PropertyAcl acl;
+        if (parsePropertyId(token.substr(2), propGroup, &acl.propId)
+            && parseUid(strUid, &acl.uid)
+            && parseAccess(strAccess, &acl.access)) {
+            propertyAclMap->emplace(acl.propId, std::move(acl));
+        } else {
+            return false;
+        }
+    } else {
+        ALOGW("Unexpected token: %s", token.c_str());
+        return false;
+    }
+
+    return true;
+}
+
+bool AccessControlConfigParser::parsePropertyGroup(
+        char group, VehiclePropertyGroup* outPropertyGroup) const {
+    switch (group) {
+        case 'S':  // Fall through.
+        case 's':
+            *outPropertyGroup = VehiclePropertyGroup::SYSTEM;
+            break;
+        case 'V':  // Fall through.
+        case 'v':
+            *outPropertyGroup = VehiclePropertyGroup::VENDOR;
+            break;
+        default:
+            ALOGW("Unexpected group: %c", group);
+            return false;
+    }
+    return true;
+}
+
+bool AccessControlConfigParser::parsePropertyId(
+        const std::string& strPropId,
+        VehiclePropertyGroup propertyGroup,
+        VehicleProperty* outVehicleProperty) const {
+    int propId;
+    if (!parseInt(strPropId.c_str(), &propId)) {
+        ALOGW("Failed to convert property id to integer: %s",
+              strPropId.c_str());
+        return false;
+    }
+    propId |= static_cast<int>(propertyGroup);
+    auto it = mStrippedToVehiclePropertyMap.find(propId);
+    if (it == mStrippedToVehiclePropertyMap.end()) {
+        ALOGW("Property Id not found or not supported: 0x%x", propId);
+        return false;
+    }
+    *outVehicleProperty = it->second;
+    return true;
+}
+
+bool AccessControlConfigParser::parseInt(const char* strValue,
+                                         int* outIntValue) {
+    char* end;
+    long num = std::strtol(strValue, &end, 0 /* auto detect base */);
+    bool success = *end == 0 && errno != ERANGE;
+    if (success) {
+        *outIntValue = static_cast<int>(num);
+    }
+
+    return success;
+}
+
+bool AccessControlConfigParser::parseUid(const std::string& strUid,
+                                         unsigned* outUid) const {
+    auto element = mUidMap.find(strUid);
+    if (element != mUidMap.end()) {
+        *outUid = element->second;
+    } else {
+        int val;
+        if (!parseInt(strUid.c_str(), &val)) {
+            ALOGW("Failed to convert UID '%s' to integer", strUid.c_str());
+            return false;
+        }
+        *outUid = static_cast<unsigned>(val);
+    }
+    return true;
+}
+
+bool AccessControlConfigParser::parseAccess(
+        const std::string& strAccess, VehiclePropertyAccess* outAccess) const {
+    if (strAccess.size() == 0 || strAccess.size() > 2) {
+        ALOGW("Unknown access mode '%s'", strAccess.c_str());
+        return false;
+    }
+    int32_t access = static_cast<int32_t>(VehiclePropertyAccess::NONE);
+    for (char c : strAccess) {
+        if (c == 'R' || c == 'r') {
+            access |= VehiclePropertyAccess::READ;
+        } else if (c == 'W' || c == 'w') {
+            access |= VehiclePropertyAccess::WRITE;
+        } else {
+            ALOGW("Unknown access mode: %c", c);
+            return false;
+        }
+    }
+    *outAccess = static_cast<VehiclePropertyAccess>(access);
+    return true;
+}
+
+void AccessControlConfigParser::split(const std::string& line,
+                                      std::list<std::string>* outTokens) {
+    outTokens->clear();
+    std::istringstream iss(line);
+
+    while (!iss.eof()) {
+        std::string token;
+        iss >> token;
+        outTokens->push_back(std::move(token));
+    }
+}
+
+std::string AccessControlConfigParser::readNextToken(
+        std::list<std::string>* tokens) const {
+    if (tokens->empty()) {
+        return "";
+    }
+
+    std::string token = tokens->front();
+    tokens->pop_front();
+    return token;
+}
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace hardware
+}  // namespace android
diff --git a/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.h b/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.h
new file mode 100644
index 0000000..17cbbd6
--- /dev/null
+++ b/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 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 android_hardware_vehicle_V2_0_AccessControlConfigParser_H_
+#define android_hardware_vehicle_V2_0_AccessControlConfigParser_H_
+
+#include <string>
+#include <vector>
+#include <unordered_map>
+#include <list>
+#include <android/hardware/vehicle/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace vehicle {
+namespace V2_0 {
+
+struct PropertyAcl {
+    VehicleProperty propId;
+    unsigned uid;
+    VehiclePropertyAccess access;
+};
+
+using PropertyAclMap = std::unordered_multimap<VehicleProperty, PropertyAcl>;
+
+/**
+ * Parser for per-property access control in vehicle HAL.
+ *
+ * It supports the following format:
+ *   Set ALIAS_NAME UID
+ *   {S,V}:0x0305   {ALIAS_NAME,UID}   {R,W,RW}
+ *
+ * ALIAS_NAME is just an alias for UID
+ * S - for system properties (VehiclePropertyGroup::SYSTEM)
+ * V - for vendor properties (VehiclePropertyGroup::VENDOR)
+ *
+ * Example:
+ *
+ *   Set AID_AUDIO  1004
+ *   Set AID_MY_APP     10022
+ *
+ *   S:0x0305   AID_AUDIO   RW
+ *   S:0x0305   10021       R
+ *   V:0x0101   AID_MY_APP  R
+ */
+class AccessControlConfigParser {
+public:
+    /**
+     * Creates an instance of AccessControlConfigParser
+     *
+     * @param properties - properties supported by HAL implementation
+     */
+    AccessControlConfigParser(const std::vector<VehicleProperty>& properties);
+
+    /**
+     * Parses config content from given stream and writes results to
+     * propertyAclMap.
+     */
+    bool parseFromStream(std::istream* stream, PropertyAclMap* propertyAclMap);
+
+private:
+    bool processTokens(std::list<std::string>* tokens,
+                       PropertyAclMap* propertyAclMap);
+
+    bool parsePropertyGroup(char group,
+                            VehiclePropertyGroup* outPropertyGroup) const;
+
+    bool parsePropertyId(const std::string& strPropId,
+                                VehiclePropertyGroup propertyGroup,
+                                VehicleProperty* outVehicleProperty) const;
+
+    bool parseUid(const std::string& strUid, unsigned* outUid) const;
+
+    bool parseAccess(const std::string& strAccess,
+                     VehiclePropertyAccess* outAccess) const;
+
+
+    std::string readNextToken(std::list<std::string>* tokens) const;
+
+    static bool parseInt(const char* strValue, int* outIntValue);
+    static void split(const std::string& line,
+                      std::list<std::string>* outTokens);
+
+private:
+    std::unordered_map<std::string, unsigned> mUidMap {};  // Contains UID
+    // aliases.
+
+    // Map property ids w/o TYPE and AREA to VehicleProperty.
+    std::unordered_map<int, VehicleProperty> mStrippedToVehiclePropertyMap;
+};
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace hardware
+}  // namespace android
+
+#endif // android_hardware_vehicle_V2_0_AccessControlConfigParser_H_
diff --git a/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp b/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp
index 1260f20..267c515 100644
--- a/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp
+++ b/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp
@@ -22,6 +22,8 @@
 #include <hidl/Status.h>
 #include <future>
 #include <bitset>
+#include <fstream>
+#include <private/android_filesystem_config.h>
 
 #include "VehicleHalManager.h"
 
@@ -52,10 +54,8 @@
             const_cast<VehiclePropConfig *>(halConfig.data()),
             halConfig.size());
 
-    ALOGI("getAllPropConfigs calling callback");
     _hidl_cb(hidlConfigs);
 
-    ALOGI("getAllPropConfigs done");
     return Void();
 }
 
@@ -88,7 +88,7 @@
         return Void();
     }
 
-    if (!checkReadPermission(*config, getCallee())) {
+    if (!checkReadPermission(*config, getCaller())) {
         _hidl_cb(StatusCode::INVALID_ARG, kEmptyValue);
         return Void();
     }
@@ -109,7 +109,7 @@
         return StatusCode::INVALID_ARG;
     }
 
-    if (!checkWritePermission(*config, getCallee())) {
+    if (!checkWritePermission(*config, getCaller())) {
         return StatusCode::INVALID_ARG;
     }
 
@@ -194,7 +194,21 @@
                          _1, _2, _3));
 
     // Initialize index with vehicle configurations received from VehicleHal.
-    mConfigIndex.reset(new VehiclePropConfigIndex(mHal->listProperties()));
+    auto supportedPropConfigs = mHal->listProperties();
+    mConfigIndex.reset(new VehiclePropConfigIndex(supportedPropConfigs));
+
+    std::vector<VehicleProperty> supportedProperties(
+        supportedPropConfigs.size());
+    for (const auto& config : supportedPropConfigs) {
+        supportedProperties.push_back(config.prop);
+    }
+
+    AccessControlConfigParser aclParser(supportedProperties);
+    const char* configs[] = { "/system/etc/vehicle_access.conf",
+                              "/vendor/etc/vehicle_access.conf" };
+    for (const char* filename : configs) {
+        readAndParseAclConfig(filename, &aclParser, &mPropertyAclMap);
+    }
 }
 
 VehicleHalManager::~VehicleHalManager() {
@@ -292,24 +306,43 @@
     return true;
 }
 
+bool checkAcl(const PropertyAclMap& aclMap,
+              uid_t callerUid,
+              VehicleProperty propertyId,
+              VehiclePropertyAccess requiredAccess) {
+    if (callerUid == AID_SYSTEM && isSystemProperty(propertyId)) {
+        return true;
+    }
+
+    auto range = aclMap.equal_range(propertyId);
+    for (auto it = range.first; it != range.second; ++it) {
+        auto& acl = it->second;
+        if (acl.uid == callerUid && (acl.access & requiredAccess)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 bool VehicleHalManager::checkWritePermission(const VehiclePropConfig &config,
-                                             const Callee& callee) {
+                                             const Caller& caller) const {
     if (!(config.access & VehiclePropertyAccess::WRITE)) {
         ALOGW("Property 0%x has no write access", config.prop);
         return false;
     }
-    //TODO(pavelm): check pid/uid has write access
-    return true;
+    return checkAcl(mPropertyAclMap, caller.uid, config.prop,
+                    VehiclePropertyAccess::WRITE);
 }
 
 bool VehicleHalManager::checkReadPermission(const VehiclePropConfig &config,
-                                            const Callee& callee) {
+                                            const Caller& caller) const {
     if (!(config.access & VehiclePropertyAccess::READ)) {
         ALOGW("Property 0%x has no read access", config.prop);
         return false;
     }
-    //TODO(pavelm): check pid/uid has read access
-    return true;
+
+    return checkAcl(mPropertyAclMap, caller.uid, config.prop,
+                    VehiclePropertyAccess::READ);
 }
 
 void VehicleHalManager::handlePropertySetEvent(const VehiclePropValue& value) {
@@ -326,13 +359,24 @@
            ? &mConfigIndex->getConfig(prop) : nullptr;
 }
 
-Callee VehicleHalManager::getCallee() {
-    Callee callee;
+Caller VehicleHalManager::getCaller() {
+    Caller caller;
     IPCThreadState* self = IPCThreadState::self();
-    callee.pid = self->getCallingPid();
-    callee.uid = self->getCallingUid();
+    caller.pid = self->getCallingPid();
+    caller.uid = self->getCallingUid();
 
-    return callee;
+    return caller;
+}
+
+void VehicleHalManager::readAndParseAclConfig(const char* filename,
+                                              AccessControlConfigParser* parser,
+                                              PropertyAclMap* outAclMap) {
+    std::ifstream file(filename);
+    if (file.is_open()) {
+        ALOGI("Parsing file: %s", filename);
+        parser->parseFromStream(&file, outAclMap);
+        file.close();
+    }
 }
 
 }  // namespace V2_0
diff --git a/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h b/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h
index 8353679..cb846c9 100644
--- a/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h
+++ b/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h
@@ -29,10 +29,11 @@
 
 #include <android/hardware/vehicle/2.0/IVehicle.h>
 
-#include "VehicleHal.h"
-#include "VehiclePropConfigIndex.h"
+#include "AccessControlConfigParser.h"
 #include "ConcurrentQueue.h"
 #include "SubscriptionManager.h"
+#include "VehicleHal.h"
+#include "VehiclePropConfigIndex.h"
 #include "VehicleObjectPool.h"
 
 namespace android {
@@ -40,7 +41,7 @@
 namespace vehicle {
 namespace V2_0 {
 
-struct Callee {
+struct Caller {
     pid_t pid;
     uid_t uid;
 };
@@ -95,17 +96,21 @@
 
     const VehiclePropConfig* getPropConfigOrNull(VehicleProperty prop) const;
 
+    bool checkWritePermission(const VehiclePropConfig &config,
+                              const Caller& callee) const;
+    bool checkReadPermission(const VehiclePropConfig &config,
+                             const Caller& caller) const;
+
     static bool isSubscribable(const VehiclePropConfig& config,
                                SubscribeFlags flags);
     static bool isSampleRateFixed(VehiclePropertyChangeMode mode);
     static float checkSampleRate(const VehiclePropConfig& config,
                                  float sampleRate);
-    static bool checkWritePermission(const VehiclePropConfig &config,
-                                     const Callee& callee);
-    static bool checkReadPermission(const VehiclePropConfig &config,
-                                    const Callee& callee);
+    static void readAndParseAclConfig(const char* filename,
+                                      AccessControlConfigParser* parser,
+                                      PropertyAclMap* outAclMap);
 
-    static Callee getCallee();
+    static Caller getCaller();
 
 private:
     VehicleHal* mHal;
@@ -117,6 +122,7 @@
     ConcurrentQueue<VehiclePropValuePtr> mEventQueue;
     BatchingConsumer<VehiclePropValuePtr> mBatchingConsumer;
     VehiclePropValuePool mValueObjectPool;
+    PropertyAclMap mPropertyAclMap;
 };
 
 }  // namespace V2_0
diff --git a/vehicle/2.0/types.hal b/vehicle/2.0/types.hal
index 0e0e3ea..72fa554 100644
--- a/vehicle/2.0/types.hal
+++ b/vehicle/2.0/types.hal
@@ -2136,6 +2136,8 @@
  * the expected output.
  */
 enum VehiclePropertyAccess : int32_t {
+  NONE = 0x00,
+
   READ = 0x01,
   WRITE = 0x02,
   READ_WRITE = 0x03,