1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/android/usage_stats/usage_stats_bridge.h"
6
7 #include <utility>
8
9 #include "base/android/callback_android.h"
10 #include "base/android/jni_array.h"
11 #include "base/android/jni_string.h"
12 #include "base/time/time.h"
13 #include "chrome/android/chrome_jni_headers/UsageStatsBridge_jni.h"
14 #include "chrome/browser/android/usage_stats/usage_stats_database.h"
15 #include "chrome/browser/android/usage_stats/website_event.pb.h"
16 #include "chrome/browser/history/history_service_factory.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/profiles/profile_android.h"
19 #include "chrome/common/pref_names.h"
20 #include "components/history/core/browser/history_service.h"
21 #include "components/pref_registry/pref_registry_syncable.h"
22
23 using base::android::AttachCurrentThread;
24 using base::android::JavaParamRef;
25 using base::android::JavaRef;
26 using base::android::ScopedJavaLocalRef;
27 using base::android::ToJavaArrayOfByteArray;
28 using base::android::ToJavaArrayOfStrings;
29
30 namespace usage_stats {
31
32 namespace {
33
isSuccess(UsageStatsDatabase::Error error)34 bool isSuccess(UsageStatsDatabase::Error error) {
35 return error == UsageStatsDatabase::Error::kNoError;
36 }
37
38 } // namespace
39
JNI_UsageStatsBridge_Init(JNIEnv * env,const JavaParamRef<jobject> & j_this,const JavaParamRef<jobject> & j_profile)40 static jlong JNI_UsageStatsBridge_Init(JNIEnv* env,
41 const JavaParamRef<jobject>& j_this,
42 const JavaParamRef<jobject>& j_profile) {
43 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
44
45 std::unique_ptr<UsageStatsDatabase> usage_stats_database =
46 std::make_unique<UsageStatsDatabase>(profile);
47
48 UsageStatsBridge* native_usage_stats_bridge =
49 new UsageStatsBridge(std::move(usage_stats_database), profile, j_this);
50
51 return reinterpret_cast<intptr_t>(native_usage_stats_bridge);
52 }
53
UsageStatsBridge(std::unique_ptr<UsageStatsDatabase> usage_stats_database,Profile * profile,const JavaRef<jobject> & j_this)54 UsageStatsBridge::UsageStatsBridge(
55 std::unique_ptr<UsageStatsDatabase> usage_stats_database,
56 Profile* profile,
57 const JavaRef<jobject>& j_this)
58 : usage_stats_database_(std::move(usage_stats_database)),
59 profile_(profile),
60 j_this_(ScopedJavaGlobalRef<jobject>(j_this)) {
61 history::HistoryService* history_service =
62 HistoryServiceFactory::GetForProfile(profile_,
63 ServiceAccessType::IMPLICIT_ACCESS);
64 if (history_service)
65 history_service->AddObserver(this);
66 }
67
~UsageStatsBridge()68 UsageStatsBridge::~UsageStatsBridge() {
69 history::HistoryService* history_service =
70 HistoryServiceFactory::GetForProfile(profile_,
71 ServiceAccessType::IMPLICIT_ACCESS);
72 if (history_service)
73 history_service->RemoveObserver(this);
74 }
75
Destroy(JNIEnv * env,const JavaRef<jobject> & j_this)76 void UsageStatsBridge::Destroy(JNIEnv* env, const JavaRef<jobject>& j_this) {
77 delete this;
78 }
79
GetAllEvents(JNIEnv * j_env,const JavaRef<jobject> & j_this,const JavaRef<jobject> & j_callback)80 void UsageStatsBridge::GetAllEvents(JNIEnv* j_env,
81 const JavaRef<jobject>& j_this,
82 const JavaRef<jobject>& j_callback) {
83 ScopedJavaGlobalRef<jobject> callback(j_callback);
84
85 usage_stats_database_->GetAllEvents(
86 base::BindOnce(&UsageStatsBridge::OnGetEventsDone,
87 weak_ptr_factory_.GetWeakPtr(), callback));
88 }
89
QueryEventsInRange(JNIEnv * j_env,const JavaRef<jobject> & j_this,const jlong j_start,const jlong j_end,const JavaRef<jobject> & j_callback)90 void UsageStatsBridge::QueryEventsInRange(JNIEnv* j_env,
91 const JavaRef<jobject>& j_this,
92 const jlong j_start,
93 const jlong j_end,
94 const JavaRef<jobject>& j_callback) {
95 ScopedJavaGlobalRef<jobject> callback(j_callback);
96
97 usage_stats_database_->QueryEventsInRange(
98 base::Time::FromJavaTime(j_start), base::Time::FromJavaTime(j_end),
99 base::BindOnce(&UsageStatsBridge::OnGetEventsDone,
100 weak_ptr_factory_.GetWeakPtr(), callback));
101 }
102
AddEvents(JNIEnv * j_env,const JavaRef<jobject> & j_this,const JavaRef<jobjectArray> & j_events,const JavaRef<jobject> & j_callback)103 void UsageStatsBridge::AddEvents(JNIEnv* j_env,
104 const JavaRef<jobject>& j_this,
105 const JavaRef<jobjectArray>& j_events,
106 const JavaRef<jobject>& j_callback) {
107 // Deserialize events from byte arrays to proto messages.
108 std::vector<std::string> serialized_events;
109 JavaArrayOfByteArrayToStringVector(j_env, j_events, &serialized_events);
110
111 std::vector<WebsiteEvent> events;
112 events.reserve(serialized_events.size());
113
114 for (const std::string& serialized : serialized_events) {
115 WebsiteEvent event;
116 event.ParseFromString(serialized);
117 events.emplace_back(event);
118 }
119
120 ScopedJavaGlobalRef<jobject> callback(j_callback);
121
122 usage_stats_database_->AddEvents(
123 events, base::BindOnce(&UsageStatsBridge::OnUpdateDone,
124 weak_ptr_factory_.GetWeakPtr(), callback));
125 }
126
DeleteAllEvents(JNIEnv * j_env,const JavaRef<jobject> & j_this,const JavaRef<jobject> & j_callback)127 void UsageStatsBridge::DeleteAllEvents(JNIEnv* j_env,
128 const JavaRef<jobject>& j_this,
129 const JavaRef<jobject>& j_callback) {
130 ScopedJavaGlobalRef<jobject> callback(j_callback);
131
132 usage_stats_database_->DeleteAllEvents(
133 base::BindOnce(&UsageStatsBridge::OnUpdateDone,
134 weak_ptr_factory_.GetWeakPtr(), callback));
135 }
136
DeleteEventsInRange(JNIEnv * j_env,const JavaRef<jobject> & j_this,const jlong j_start,const jlong j_end,const JavaRef<jobject> & j_callback)137 void UsageStatsBridge::DeleteEventsInRange(JNIEnv* j_env,
138 const JavaRef<jobject>& j_this,
139 const jlong j_start,
140 const jlong j_end,
141 const JavaRef<jobject>& j_callback) {
142 ScopedJavaGlobalRef<jobject> callback(j_callback);
143
144 usage_stats_database_->DeleteEventsInRange(
145 base::Time::FromJavaTime(j_start), base::Time::FromJavaTime(j_end),
146 base::BindOnce(&UsageStatsBridge::OnUpdateDone,
147 weak_ptr_factory_.GetWeakPtr(), callback));
148 }
149
DeleteEventsWithMatchingDomains(JNIEnv * j_env,const JavaRef<jobject> & j_this,const JavaRef<jobjectArray> & j_domains,const JavaRef<jobject> & j_callback)150 void UsageStatsBridge::DeleteEventsWithMatchingDomains(
151 JNIEnv* j_env,
152 const JavaRef<jobject>& j_this,
153 const JavaRef<jobjectArray>& j_domains,
154 const JavaRef<jobject>& j_callback) {
155 std::vector<std::string> domains;
156 AppendJavaStringArrayToStringVector(j_env, j_domains, &domains);
157
158 ScopedJavaGlobalRef<jobject> callback(j_callback);
159
160 usage_stats_database_->DeleteEventsWithMatchingDomains(
161 base::flat_set<std::string>(domains),
162 base::BindOnce(&UsageStatsBridge::OnUpdateDone,
163 weak_ptr_factory_.GetWeakPtr(), callback));
164 }
165
GetAllSuspensions(JNIEnv * j_env,const JavaRef<jobject> & j_this,const JavaRef<jobject> & j_callback)166 void UsageStatsBridge::GetAllSuspensions(JNIEnv* j_env,
167 const JavaRef<jobject>& j_this,
168 const JavaRef<jobject>& j_callback) {
169 ScopedJavaGlobalRef<jobject> callback(j_callback);
170
171 usage_stats_database_->GetAllSuspensions(
172 base::BindOnce(&UsageStatsBridge::OnGetAllSuspensionsDone,
173 weak_ptr_factory_.GetWeakPtr(), callback));
174 }
175
SetSuspensions(JNIEnv * j_env,const JavaRef<jobject> & j_this,const JavaRef<jobjectArray> & j_domains,const JavaRef<jobject> & j_callback)176 void UsageStatsBridge::SetSuspensions(JNIEnv* j_env,
177 const JavaRef<jobject>& j_this,
178 const JavaRef<jobjectArray>& j_domains,
179 const JavaRef<jobject>& j_callback) {
180 std::vector<std::string> domains;
181 AppendJavaStringArrayToStringVector(j_env, j_domains, &domains);
182
183 ScopedJavaGlobalRef<jobject> callback(j_callback);
184
185 usage_stats_database_->SetSuspensions(
186 domains, base::BindOnce(&UsageStatsBridge::OnUpdateDone,
187 weak_ptr_factory_.GetWeakPtr(), callback));
188 }
189
GetAllTokenMappings(JNIEnv * j_env,const JavaRef<jobject> & j_this,const JavaRef<jobject> & j_callback)190 void UsageStatsBridge::GetAllTokenMappings(JNIEnv* j_env,
191 const JavaRef<jobject>& j_this,
192 const JavaRef<jobject>& j_callback) {
193 ScopedJavaGlobalRef<jobject> callback(j_callback);
194
195 usage_stats_database_->GetAllTokenMappings(
196 base::BindOnce(&UsageStatsBridge::OnGetAllTokenMappingsDone,
197 weak_ptr_factory_.GetWeakPtr(), callback));
198 }
199
SetTokenMappings(JNIEnv * j_env,const JavaRef<jobject> & j_this,const JavaRef<jobjectArray> & j_tokens,const JavaRef<jobjectArray> & j_fqdns,const JavaRef<jobject> & j_callback)200 void UsageStatsBridge::SetTokenMappings(JNIEnv* j_env,
201 const JavaRef<jobject>& j_this,
202 const JavaRef<jobjectArray>& j_tokens,
203 const JavaRef<jobjectArray>& j_fqdns,
204 const JavaRef<jobject>& j_callback) {
205 ScopedJavaGlobalRef<jobject> callback(j_callback);
206
207 std::vector<std::string> tokens, fqdns;
208 AppendJavaStringArrayToStringVector(j_env, j_tokens, &tokens);
209 AppendJavaStringArrayToStringVector(j_env, j_fqdns, &fqdns);
210
211 DCHECK(tokens.size() == fqdns.size());
212
213 // Zip tokens (keys) and FQDNs (values) into a map.
214 UsageStatsDatabase::TokenMap mappings;
215 for (size_t i = 0; i < tokens.size(); i++) {
216 mappings.emplace(tokens[i], fqdns[i]);
217 }
218
219 usage_stats_database_->SetTokenMappings(
220 mappings, base::BindOnce(&UsageStatsBridge::OnUpdateDone,
221 weak_ptr_factory_.GetWeakPtr(), callback));
222 }
223
OnGetEventsDone(ScopedJavaGlobalRef<jobject> callback,UsageStatsDatabase::Error error,std::vector<WebsiteEvent> events)224 void UsageStatsBridge::OnGetEventsDone(ScopedJavaGlobalRef<jobject> callback,
225 UsageStatsDatabase::Error error,
226 std::vector<WebsiteEvent> events) {
227 JNIEnv* env = AttachCurrentThread();
228
229 if (!isSuccess(error)) {
230 Java_UsageStatsBridge_createEventListAndRunCallback(
231 env, ToJavaArrayOfByteArray(env, std::vector<std::string>()), callback);
232 return;
233 }
234
235 // Serialize WebsiteEvent proto messages for passing over JNI bridge as byte
236 // arrays.
237 std::vector<std::string> serialized_events;
238 serialized_events.reserve(events.size());
239
240 for (WebsiteEvent event : events) {
241 std::string serialized;
242 event.SerializeToString(&serialized);
243 serialized_events.emplace_back(serialized);
244 }
245
246 ScopedJavaLocalRef<jobjectArray> j_serialized_events =
247 ToJavaArrayOfByteArray(env, serialized_events);
248
249 // Over JNI, deserialize to list of WebsiteEvent messages, and run on given
250 // callback.
251 Java_UsageStatsBridge_createEventListAndRunCallback(env, j_serialized_events,
252 callback);
253 }
254
OnGetAllSuspensionsDone(ScopedJavaGlobalRef<jobject> callback,UsageStatsDatabase::Error error,std::vector<std::string> suspensions)255 void UsageStatsBridge::OnGetAllSuspensionsDone(
256 ScopedJavaGlobalRef<jobject> callback,
257 UsageStatsDatabase::Error error,
258 std::vector<std::string> suspensions) {
259 JNIEnv* env = AttachCurrentThread();
260
261 ScopedJavaLocalRef<jobjectArray> j_suspensions =
262 isSuccess(error) ? ToJavaArrayOfStrings(env, suspensions)
263 : ToJavaArrayOfStrings(env, std::vector<std::string>());
264
265 RunObjectCallbackAndroid(callback, j_suspensions);
266 }
267
OnGetAllTokenMappingsDone(ScopedJavaGlobalRef<jobject> callback,UsageStatsDatabase::Error error,UsageStatsDatabase::TokenMap mappings)268 void UsageStatsBridge::OnGetAllTokenMappingsDone(
269 ScopedJavaGlobalRef<jobject> callback,
270 UsageStatsDatabase::Error error,
271 UsageStatsDatabase::TokenMap mappings) {
272 JNIEnv* env = AttachCurrentThread();
273
274 if (!isSuccess(error)) {
275 Java_UsageStatsBridge_createMapAndRunCallback(
276 env, ToJavaArrayOfStrings(env, std::vector<std::string>()),
277 ToJavaArrayOfStrings(env, std::vector<std::string>()), callback);
278 return;
279 }
280
281 // Create separate vectors of keys and values from map for passing over
282 // JNI bridge as String arrays.
283 std::vector<std::string> keys, values;
284 keys.reserve(mappings.size());
285 values.reserve(mappings.size());
286
287 for (auto mapping : mappings) {
288 keys.emplace_back(std::move(mapping.first));
289 values.emplace_back(std::move(mapping.second));
290 }
291
292 ScopedJavaLocalRef<jobjectArray> j_keys = ToJavaArrayOfStrings(env, keys);
293 ScopedJavaLocalRef<jobjectArray> j_values = ToJavaArrayOfStrings(env, values);
294
295 // Over JNI, reconstruct map from keys and values, and run on given callback.
296 Java_UsageStatsBridge_createMapAndRunCallback(env, j_keys, j_values,
297 callback);
298 }
299
OnUpdateDone(ScopedJavaGlobalRef<jobject> callback,UsageStatsDatabase::Error error)300 void UsageStatsBridge::OnUpdateDone(ScopedJavaGlobalRef<jobject> callback,
301 UsageStatsDatabase::Error error) {
302 RunBooleanCallbackAndroid(callback, isSuccess(error));
303 }
304
305 // static
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)306 void UsageStatsBridge::RegisterProfilePrefs(
307 user_prefs::PrefRegistrySyncable* registry) {
308 registry->RegisterBooleanPref(prefs::kUsageStatsEnabled, false);
309 }
310
OnURLsDeleted(history::HistoryService * history_service,const history::DeletionInfo & deletion_info)311 void UsageStatsBridge::OnURLsDeleted(
312 history::HistoryService* history_service,
313 const history::DeletionInfo& deletion_info) {
314 // We ignore expirations since they're not user-initiated.
315 if (deletion_info.is_from_expiration()) {
316 return;
317 }
318
319 JNIEnv* env = AttachCurrentThread();
320
321 if (deletion_info.IsAllHistory()) {
322 Java_UsageStatsBridge_onAllHistoryDeleted(env, j_this_);
323 return;
324 }
325
326 history::DeletionTimeRange time_range = deletion_info.time_range();
327 if (time_range.IsValid()) {
328 const base::Optional<std::set<GURL>>& urls = deletion_info.restrict_urls();
329 if (urls.has_value() && urls.value().size() > 0) {
330 std::vector<std::string> domains;
331 domains.reserve(urls.value().size());
332 for (const auto& gurl : urls.value()) {
333 domains.push_back(gurl.host());
334 }
335 Java_UsageStatsBridge_onHistoryDeletedForDomains(
336 env, j_this_, ToJavaArrayOfStrings(env, domains));
337 } else {
338 int64_t startTimeMs = time_range.begin().ToJavaTime();
339 int64_t endTimeMs = time_range.end().ToJavaTime();
340
341 Java_UsageStatsBridge_onHistoryDeletedInRange(env, j_this_, startTimeMs,
342 endTimeMs);
343 }
344
345 return;
346 }
347 }
348
349 } // namespace usage_stats
350