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/AppOpsSession.h>
18 #include <media/AttrSourceIter.h>
19
20 #include <binder/AppOpsManager.h>
21 #include <binder/PermissionController.h>
22
23 using ::android::content::AttributionSourceState;
24
25 namespace android::media::permission {
26
27 // Package name param is unreliable (can be empty), but we should only get valid events based on
28 // how we register the listener.
opChanged(int32_t op,int32_t,const String16 &,const String16 &)29 binder::Status DefaultAppOpsFacade::OpMonitor::opChanged(int32_t op, int32_t, const String16&,
30 const String16&) {
31 if (mOps.attributedOp != op && mOps.additionalOp != op) return binder::Status::ok();
32 DefaultAppOpsFacade x{};
33 const auto allowed = x.checkAccess(mAttr, mOps);
34 std::lock_guard l_{mLock};
35 if (mCb != nullptr) {
36 mCb(allowed);
37 }
38 return binder::Status::ok();
39 }
40
startAccess(const ValidatedAttributionSourceState & attr_,Ops ops)41 bool DefaultAppOpsFacade::startAccess(const ValidatedAttributionSourceState& attr_, Ops ops) {
42 const AttributionSourceState& attr = attr_;
43 // TODO(b/384845037) no support for additional op at the moment
44 if (ops.attributedOp == AppOpsManager::OP_NONE) return true; // nothing to do
45 // TODO(b/384845037) caching and sync up-call marking
46 AppOpsManager ap{};
47 return ap.startOpNoThrow(
48 /*op=*/ ops.attributedOp,
49 /*uid=*/ attr.uid,
50 /*callingPackage=*/ String16{attr.packageName.value_or("").c_str()},
51 /*startIfModeDefault=*/ false,
52 /*attributionTag=*/ attr.attributionTag.has_value() ?
53 String16{attr.attributionTag.value().c_str()}
54 : String16{},
55 /*message=*/ String16{"AppOpsSession start"})
56 == AppOpsManager::MODE_ALLOWED;
57 }
58
stopAccess(const ValidatedAttributionSourceState & attr_,Ops ops)59 void DefaultAppOpsFacade::stopAccess(const ValidatedAttributionSourceState& attr_, Ops ops) {
60 const AttributionSourceState& attr = attr_;
61 // TODO(b/384845037) caching and sync up-call marking
62 AppOpsManager ap{};
63 return ap.finishOp(
64 /*op=*/ ops.attributedOp,
65 /*uid=*/ attr.uid,
66 /*callingPackage=*/ String16{attr.packageName.value_or("").c_str()},
67 /*attributionTag=*/ attr.attributionTag.has_value() ?
68 String16{attr.attributionTag.value().c_str()}
69 : String16{});
70 }
71
checkAccess(const ValidatedAttributionSourceState & attr,Ops ops)72 bool DefaultAppOpsFacade::checkAccess(const ValidatedAttributionSourceState& attr, Ops ops) {
73 const auto check = [&](int32_t op) -> bool {
74 if (op == AppOpsManager::OP_NONE) return true;
75 return std::all_of(
76 AttrSourceIter::cbegin(attr), AttrSourceIter::cend(), [&](const auto& x) {
77 return AppOpsManager{}.checkOp(op, x.uid,
78 String16{x.packageName.value_or("").c_str()}) ==
79 AppOpsManager::MODE_ALLOWED;
80 });
81 };
82 return check(ops.attributedOp) && check(ops.additionalOp);
83 }
84
addChangeCallback(const ValidatedAttributionSourceState & attr,Ops ops,std::function<void (bool)> cb)85 uintptr_t DefaultAppOpsFacade::addChangeCallback(const ValidatedAttributionSourceState& attr,
86 Ops ops, std::function<void(bool)> cb) {
87 const auto listener = sp<OpMonitor>::make(attr, ops, std::move(cb));
88 const auto reg = [&](int32_t op) {
89 std::for_each(AttrSourceIter::cbegin(attr), AttrSourceIter::cend(),
90 [&listener, op](const auto& x) {
91 AppOpsManager{}.startWatchingMode(
92 op, String16{x.packageName.value_or("").c_str()},
93 AppOpsManager::WATCH_FOREGROUND_CHANGES, listener);
94 });
95 };
96 if (ops.attributedOp != AppOpsManager::OP_NONE) reg(ops.attributedOp);
97 if (ops.additionalOp != AppOpsManager::OP_NONE) reg(ops.additionalOp);
98 std::lock_guard l_{sMapLock};
99 const auto cookie = reinterpret_cast<uintptr_t>(listener.get());
100 sCbMap[cookie] = std::move(listener);
101 return cookie;
102 }
103
removeChangeCallback(uintptr_t ptr)104 void DefaultAppOpsFacade::removeChangeCallback(uintptr_t ptr) {
105 sp<OpMonitor> monitor;
106 {
107 std::lock_guard l_{sMapLock};
108 if (const auto iter = sCbMap.find(ptr); iter != sCbMap.end()) {
109 monitor = std::move(iter->second);
110 sCbMap.erase(iter);
111 }
112 }
113 LOG_ALWAYS_FATAL_IF(monitor == nullptr, "Unexpected nullptr in cb map");
114 monitor->stopListening();
115 // Callbacks are stored via binder identity in AppOpsService, so unregistering the callback
116 // removes it regardless of how many calls to startWatchingMode occurred
117 AppOpsManager{}.stopWatchingMode(monitor);
118 }
119
120 } // namespace android::media::permission
121