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