blob: 8659f2c27851de125f80610f48c2a6647092c521 [file] [log] [blame]
Atneya Nair9f91a5e2024-05-09 16:25:05 -07001/*
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
Atneya Nair9f91a5e2024-05-09 16:25:05 -070027using ::android::binder::Status;
Atneya Nairb05f2f12024-06-05 21:00:21 -070028using ::android::error::BinderResult;
29using ::android::error::unexpectedExceptionCode;
Atneya Nair9f91a5e2024-05-09 16:25:05 -070030
31namespace com::android::media::permission {
32static 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 // These packages are not handled by AppOps, but labeling may be useful for us
48 case AID_RADIO:
49 return "telephony";
50 case AID_BLUETOOTH:
51 return "bluetooth";
52 default:
53 return std::nullopt;
54 }
55}
56
57// -- Begin Binder methods
58Status NativePermissionController::populatePackagesForUids(
59 const std::vector<UidPackageState>& initialPackageStates) {
60 std::lock_guard l{m_};
61 if (!is_package_populated_) is_package_populated_ = true;
62 package_map_.clear();
63 std::transform(initialPackageStates.begin(), initialPackageStates.end(),
64 std::inserter(package_map_, package_map_.end()),
65 [](const auto& x) -> std::pair<uid_t, std::vector<std::string>> {
66 return {x.uid, x.packageNames};
67 });
68 std::erase_if(package_map_, [](const auto& x) { return x.second.empty(); });
69 return Status::ok();
70}
71
72Status NativePermissionController::updatePackagesForUid(const UidPackageState& newPackageState) {
73 std::lock_guard l{m_};
74 package_map_.insert_or_assign(newPackageState.uid, newPackageState.packageNames);
75 const auto& cursor = package_map_.find(newPackageState.uid);
76
77 if (newPackageState.packageNames.empty()) {
78 if (cursor != package_map_.end()) {
79 package_map_.erase(cursor);
80 }
81 } else {
82 if (cursor != package_map_.end()) {
83 cursor->second = newPackageState.packageNames;
84 } else {
85 package_map_.insert({newPackageState.uid, newPackageState.packageNames});
86 }
87 }
88 return Status::ok();
89}
90
Atneya Nairc23be502024-05-13 10:28:07 -070091Status NativePermissionController::populatePermissionState(PermissionEnum perm,
92 const std::vector<int>& uids) {
93 if (perm >= PermissionEnum::ENUM_SIZE || static_cast<int>(perm) < 0) {
94 return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
95 }
96 std::lock_guard l{m_};
97 auto& cursor = permission_map_[static_cast<size_t>(perm)];
98 cursor = std::vector<uid_t>{uids.begin(), uids.end()};
99 // should be sorted
100 std::sort(cursor.begin(), cursor.end());
101 return Status::ok();
102}
103
Atneya Nair9f91a5e2024-05-09 16:25:05 -0700104// -- End Binder methods
105
Atneya Nairb05f2f12024-06-05 21:00:21 -0700106BinderResult<std::vector<std::string>> NativePermissionController::getPackagesForUid(
107 uid_t uid) const {
Atneya Nair9f91a5e2024-05-09 16:25:05 -0700108 uid = uid % AID_USER_OFFSET;
109 const auto fixed_package_opt = getFixedPackageName(uid);
110 if (fixed_package_opt.has_value()) {
Atneya Nairb05f2f12024-06-05 21:00:21 -0700111 return BinderResult<std::vector<std::string>>{std::in_place_t{},
112 {fixed_package_opt.value()}};
Atneya Nair9f91a5e2024-05-09 16:25:05 -0700113 }
114 std::lock_guard l{m_};
Atneya Nairb05f2f12024-06-05 21:00:21 -0700115 if (!is_package_populated_) {
116 return unexpectedExceptionCode(
117 Status::EX_ILLEGAL_STATE,
118 "NPC::getPackagesForUid: controller never populated by system_server");
119 }
Atneya Nair9f91a5e2024-05-09 16:25:05 -0700120 const auto cursor = package_map_.find(uid);
121 if (cursor != package_map_.end()) {
122 return cursor->second;
123 } else {
Atneya Nairb05f2f12024-06-05 21:00:21 -0700124 return unexpectedExceptionCode(
125 Status::EX_ILLEGAL_ARGUMENT,
126 ("NPC::getPackagesForUid: uid not found: " + std::to_string(uid)).c_str());
Atneya Nair9f91a5e2024-05-09 16:25:05 -0700127 }
128}
129
Atneya Nairb05f2f12024-06-05 21:00:21 -0700130BinderResult<bool> NativePermissionController::validateUidPackagePair(
Atneya Nair9f91a5e2024-05-09 16:25:05 -0700131 uid_t uid, const std::string& packageName) const {
132 uid = uid % AID_USER_OFFSET;
133 const auto fixed_package_opt = getFixedPackageName(uid);
134 if (fixed_package_opt.has_value()) {
135 return packageName == fixed_package_opt.value();
136 }
137 std::lock_guard l{m_};
Atneya Nairb05f2f12024-06-05 21:00:21 -0700138 if (!is_package_populated_) {
139 return unexpectedExceptionCode(
140 Status::EX_ILLEGAL_STATE,
141 "NPC::validatedUidPackagePair: controller never populated by system_server");
142 }
Atneya Nair9f91a5e2024-05-09 16:25:05 -0700143 const auto cursor = package_map_.find(uid);
144 return (cursor != package_map_.end()) &&
145 (std::find(cursor->second.begin(), cursor->second.end(), packageName) !=
146 cursor->second.end());
147}
Atneya Nairc23be502024-05-13 10:28:07 -0700148
Atneya Nairb05f2f12024-06-05 21:00:21 -0700149BinderResult<bool> NativePermissionController::checkPermission(PermissionEnum perm,
150 uid_t uid) const {
Atneya Nairc23be502024-05-13 10:28:07 -0700151 std::lock_guard l{m_};
152 const auto& uids = permission_map_[static_cast<size_t>(perm)];
153 if (!uids.empty()) {
154 return std::binary_search(uids.begin(), uids.end(), uid);
155 } else {
Atneya Nairb05f2f12024-06-05 21:00:21 -0700156 return unexpectedExceptionCode(
157 Status::EX_ILLEGAL_STATE,
158 "NPC::checkPermission: controller never populated by system_server");
Atneya Nairc23be502024-05-13 10:28:07 -0700159 }
160}
161
Atneya Nair9f91a5e2024-05-09 16:25:05 -0700162} // namespace com::android::media::permission