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