1 /*
2 * Copyright 2020 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 #define LOG_TAG "BluetoothActivityAttributionJni"
18
19 #include <string.h>
20
21 #include <shared_mutex>
22
23 #include "base/logging.h"
24 #include "com_android_bluetooth.h"
25 #include "hardware/bt_activity_attribution.h"
26
27 using bluetooth::activity_attribution::ActivityAttributionCallbacks;
28 using bluetooth::activity_attribution::ActivityAttributionInterface;
29
30 namespace android {
31 static jmethodID method_onWakeup;
32 static jmethodID method_onActivityLogsReady;
33
34 static ActivityAttributionInterface* sActivityAttributionInterface = nullptr;
35 static std::shared_timed_mutex interface_mutex;
36
37 static jobject mCallbacksObj = nullptr;
38 static std::shared_timed_mutex callbacks_mutex;
39
40 class ActivityAttributionCallbacksImpl : public ActivityAttributionCallbacks {
41 public:
42 ~ActivityAttributionCallbacksImpl() = default;
43
OnWakeup(const Activity activity,const RawAddress & bd_addr)44 void OnWakeup(const Activity activity, const RawAddress& bd_addr) override {
45 LOG(INFO) << __func__;
46
47 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
48 CallbackEnv sCallbackEnv(__func__);
49 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
50
51 ScopedLocalRef<jbyteArray> addr(
52 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
53 if (!addr.get()) {
54 LOG(ERROR)
55 << "Failed to allocate jbyteArray for bd_addr of wakeup callback";
56 return;
57 }
58
59 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
60 (jbyte*)&bd_addr);
61 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onWakeup, (jint)activity,
62 addr.get());
63 }
64
OnActivityLogsReady(const std::vector<BtaaAggregationEntry> logs)65 void OnActivityLogsReady(
66 const std::vector<BtaaAggregationEntry> logs) override {
67 LOG(INFO) << __func__;
68
69 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
70 CallbackEnv sCallbackEnv(__func__);
71 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
72
73 jsize logs_size = logs.size() * sizeof(BtaaAggregationEntry);
74 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
75 sCallbackEnv->NewByteArray(logs_size));
76 if (!addr.get()) {
77 LOG(ERROR) << "Failed to allocate jbyteArray for logs from activity "
78 "logging callback";
79 return;
80 }
81
82 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, logs_size,
83 (jbyte*)logs.data());
84 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onActivityLogsReady,
85 addr.get());
86 }
87 };
88
89 static ActivityAttributionCallbacksImpl sActivityAttributionCallbacks;
90
classInitNative(JNIEnv * env,jclass clazz)91 static void classInitNative(JNIEnv* env, jclass clazz) {
92 method_onWakeup = env->GetMethodID(clazz, "onWakeup", "(I[B)V");
93 method_onActivityLogsReady =
94 env->GetMethodID(clazz, "onActivityLogsReady", "([B)V");
95
96 LOG(INFO) << __func__ << ": succeeds";
97 }
98
initNative(JNIEnv * env,jobject object)99 static void initNative(JNIEnv* env, jobject object) {
100 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
101 std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
102 const bt_interface_t* btInf = getBluetoothInterface();
103 if (btInf == nullptr) {
104 LOG(ERROR) << "Bluetooth module is not loaded";
105 return;
106 }
107
108 if (sActivityAttributionInterface != nullptr) {
109 LOG(INFO)
110 << "Cleaning up ActivityAttribution Interface before initializing...";
111 sActivityAttributionInterface->Cleanup();
112 sActivityAttributionInterface = nullptr;
113 }
114
115 if (mCallbacksObj != nullptr) {
116 LOG(INFO) << "Cleaning up ActivityAttribution callback object";
117 env->DeleteGlobalRef(mCallbacksObj);
118 mCallbacksObj = nullptr;
119 }
120
121 if ((mCallbacksObj = env->NewGlobalRef(object)) == nullptr) {
122 LOG(ERROR)
123 << "Failed to allocate Global Ref for ActivityAttribution Callbacks";
124 return;
125 }
126
127 sActivityAttributionInterface =
128 (ActivityAttributionInterface*)btInf->get_profile_interface(
129 BT_ACTIVITY_ATTRIBUTION_ID);
130 if (sActivityAttributionInterface == nullptr) {
131 LOG(ERROR) << "Failed to get ActivityAttribution Interface";
132 return;
133 }
134
135 sActivityAttributionInterface->RegisterCallbacks(
136 &sActivityAttributionCallbacks);
137 }
138
cleanupNative(JNIEnv * env,jobject object)139 static void cleanupNative(JNIEnv* env, jobject object) {
140 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
141 std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
142
143 const bt_interface_t* btInf = getBluetoothInterface();
144 if (btInf == nullptr) {
145 LOG(ERROR) << "Bluetooth module is not loaded";
146 return;
147 }
148
149 if (sActivityAttributionInterface != nullptr) {
150 sActivityAttributionInterface->Cleanup();
151 sActivityAttributionInterface = nullptr;
152 }
153
154 if (mCallbacksObj != nullptr) {
155 env->DeleteGlobalRef(mCallbacksObj);
156 mCallbacksObj = nullptr;
157 }
158 }
159
160 static JNINativeMethod sMethods[] = {
161 {"classInitNative", "()V", (void*)classInitNative},
162 {"initNative", "()V", (void*)initNative},
163 {"cleanupNative", "()V", (void*)cleanupNative},
164 };
165
register_com_android_bluetooth_btservice_activity_attribution(JNIEnv * env)166 int register_com_android_bluetooth_btservice_activity_attribution(JNIEnv* env) {
167 return jniRegisterNativeMethods(
168 env,
169 "com/android/bluetooth/btservice/activityattribution/"
170 "ActivityAttributionNativeInterface",
171 sMethods, NELEM(sMethods));
172 }
173
174 } // namespace android
175