xref: /aosp_15_r20/frameworks/av/media/libaudiopermission/NativePermissionController.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <media/NativePermissionController.h>
18 
19 #include <algorithm>
20 #include <optional>
21 #include <utility>
22 
23 #include <android-base/expected.h>
24 #include <cutils/android_filesystem_config.h>
25 #include <utils/Errors.h>
26 
27 using ::android::binder::Status;
28 using ::android::error::BinderResult;
29 using ::android::error::unexpectedExceptionCode;
30 
31 namespace com::android::media::permission {
getFixedPackageName(uid_t uid)32 static std::optional<std::string> getFixedPackageName(uid_t uid) {
33     // These values are in sync with AppOpsService
34     switch (uid % AID_USER_OFFSET) {
35         case AID_ROOT:
36             return "root";
37         case AID_SYSTEM:
38             return "system";
39         case AID_SHELL:
40             return "shell";
41         case AID_MEDIA:
42             return "media";
43         case AID_AUDIOSERVER:
44             return "audioserver";
45         case AID_CAMERASERVER:
46             return "cameraserver";
47         default:
48             return std::nullopt;
49     }
50 }
51 
52 // -- Begin Binder methods
populatePackagesForUids(const std::vector<UidPackageState> & initialPackageStates)53 Status NativePermissionController::populatePackagesForUids(
54         const std::vector<UidPackageState>& initialPackageStates) {
55     std::lock_guard l{m_};
56     if (!is_package_populated_) is_package_populated_ = true;
57     package_map_.clear();
58     std::transform(initialPackageStates.begin(), initialPackageStates.end(),
59                    std::inserter(package_map_, package_map_.end()),
60                    [](const auto& x) -> std::pair<uid_t, std::vector<std::string>> {
61                        return {x.uid, x.packageNames};
62                    });
63     std::erase_if(package_map_, [](const auto& x) { return x.second.empty(); });
64     return Status::ok();
65 }
66 
updatePackagesForUid(const UidPackageState & newPackageState)67 Status NativePermissionController::updatePackagesForUid(const UidPackageState& newPackageState) {
68     std::lock_guard l{m_};
69     package_map_.insert_or_assign(newPackageState.uid, newPackageState.packageNames);
70     const auto& cursor = package_map_.find(newPackageState.uid);
71 
72     if (newPackageState.packageNames.empty()) {
73         if (cursor != package_map_.end()) {
74             package_map_.erase(cursor);
75         }
76     } else {
77         if (cursor != package_map_.end()) {
78             cursor->second = newPackageState.packageNames;
79         } else {
80             package_map_.insert({newPackageState.uid, newPackageState.packageNames});
81         }
82     }
83     return Status::ok();
84 }
85 
populatePermissionState(PermissionEnum perm,const std::vector<int> & uids)86 Status NativePermissionController::populatePermissionState(PermissionEnum perm,
87                                                            const std::vector<int>& uids) {
88     if (perm >= PermissionEnum::ENUM_SIZE || static_cast<int>(perm) < 0) {
89         return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
90     }
91     std::lock_guard l{m_};
92     auto& cursor = permission_map_[static_cast<size_t>(perm)];
93     cursor = std::vector<uid_t>{uids.begin(), uids.end()};
94     // should be sorted
95     std::sort(cursor.begin(), cursor.end());
96     return Status::ok();
97 }
98 
99 // -- End Binder methods
100 
getPackagesForUid(uid_t uid) const101 BinderResult<std::vector<std::string>> NativePermissionController::getPackagesForUid(
102         uid_t uid) const {
103     uid = uid % AID_USER_OFFSET;
104     const auto fixed_package_opt = getFixedPackageName(uid);
105     if (fixed_package_opt.has_value()) {
106         return BinderResult<std::vector<std::string>>{std::in_place_t{},
107                                                       {fixed_package_opt.value()}};
108     }
109     std::lock_guard l{m_};
110     if (!is_package_populated_) {
111         return unexpectedExceptionCode(
112                 Status::EX_ILLEGAL_STATE,
113                 "NPC::getPackagesForUid: controller never populated by system_server");
114     }
115     const auto cursor = package_map_.find(uid);
116     if (cursor != package_map_.end()) {
117         return cursor->second;
118     } else {
119         return unexpectedExceptionCode(
120                 Status::EX_ILLEGAL_ARGUMENT,
121                 ("NPC::getPackagesForUid: uid not found: " + std::to_string(uid)).c_str());
122     }
123 }
124 
validateUidPackagePair(uid_t uid,const std::string & packageName) const125 BinderResult<bool> NativePermissionController::validateUidPackagePair(
126         uid_t uid, const std::string& packageName) const {
127     if (uid == AID_ROOT || uid == AID_SYSTEM) return true;
128     uid = uid % AID_USER_OFFSET;
129     const auto fixed_package_opt = getFixedPackageName(uid);
130     if (fixed_package_opt.has_value()) {
131         return (uid == AID_ROOT || uid == AID_SYSTEM) ? true :
132                 packageName == fixed_package_opt.value();
133     }
134     std::lock_guard l{m_};
135     if (!is_package_populated_) {
136         return unexpectedExceptionCode(
137                 Status::EX_ILLEGAL_STATE,
138                 "NPC::validatedUidPackagePair: controller never populated by system_server");
139     }
140     const auto cursor = package_map_.find(uid);
141     return (cursor != package_map_.end()) &&
142            (std::find(cursor->second.begin(), cursor->second.end(), packageName) !=
143             cursor->second.end());
144 }
145 
checkPermission(PermissionEnum perm,uid_t uid) const146 BinderResult<bool> NativePermissionController::checkPermission(PermissionEnum perm,
147                                                                uid_t uid) const {
148     if (uid == AID_ROOT || uid == AID_SYSTEM || uid == getuid()) return true;
149     std::lock_guard l{m_};
150     const auto& uids = permission_map_[static_cast<size_t>(perm)];
151     if (!uids.empty()) {
152         return std::binary_search(uids.begin(), uids.end(), uid);
153     } else {
154         return unexpectedExceptionCode(
155                 Status::EX_ILLEGAL_STATE,
156                 "NPC::checkPermission: controller never populated by system_server");
157     }
158 }
159 
160 }  // namespace com::android::media::permission
161