blob: 5835e4568ce4a68f4a5a46cd7f2b954079c560ee [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/android/usage_stats/usage_stats_bridge.h"
#include <utility>
#include "base/android/callback_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/time/time.h"
#include "chrome/browser/android/usage_stats/usage_stats_database.h"
#include "chrome/browser/android/usage_stats/website_event.pb.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_android.h"
#include "chrome/common/pref_names.h"
#include "components/history/core/browser/history_service.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "jni/UsageStatsBridge_jni.h"
using base::android::AttachCurrentThread;
using base::android::JavaParamRef;
using base::android::JavaRef;
using base::android::ScopedJavaLocalRef;
using base::android::ToJavaArrayOfByteArray;
using base::android::ToJavaArrayOfStrings;
namespace usage_stats {
namespace {
bool isSuccess(UsageStatsDatabase::Error error) {
return error == UsageStatsDatabase::Error::kNoError;
}
} // namespace
static jlong JNI_UsageStatsBridge_Init(JNIEnv* env,
const JavaParamRef<jobject>& j_this,
const JavaParamRef<jobject>& j_profile) {
Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
std::unique_ptr<UsageStatsDatabase> usage_stats_database =
std::make_unique<UsageStatsDatabase>(profile);
UsageStatsBridge* native_usage_stats_bridge =
new UsageStatsBridge(std::move(usage_stats_database), profile, j_this);
return reinterpret_cast<intptr_t>(native_usage_stats_bridge);
}
UsageStatsBridge::UsageStatsBridge(
std::unique_ptr<UsageStatsDatabase> usage_stats_database,
Profile* profile,
const JavaRef<jobject>& j_this)
: usage_stats_database_(std::move(usage_stats_database)),
profile_(profile),
j_this_(ScopedJavaGlobalRef<jobject>(j_this)),
weak_ptr_factory_(this) {
history::HistoryService* history_service =
HistoryServiceFactory::GetForProfile(profile_,
ServiceAccessType::IMPLICIT_ACCESS);
if (history_service)
history_service->AddObserver(this);
}
UsageStatsBridge::~UsageStatsBridge() {
history::HistoryService* history_service =
HistoryServiceFactory::GetForProfile(profile_,
ServiceAccessType::IMPLICIT_ACCESS);
if (history_service)
history_service->RemoveObserver(this);
}
void UsageStatsBridge::Destroy(JNIEnv* env, const JavaRef<jobject>& j_this) {
delete this;
}
void UsageStatsBridge::GetAllEvents(JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const JavaRef<jobject>& j_callback) {
ScopedJavaGlobalRef<jobject> callback(j_callback);
usage_stats_database_->GetAllEvents(
base::BindOnce(&UsageStatsBridge::OnGetEventsDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void UsageStatsBridge::QueryEventsInRange(JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const jlong j_start,
const jlong j_end,
const JavaRef<jobject>& j_callback) {
ScopedJavaGlobalRef<jobject> callback(j_callback);
usage_stats_database_->QueryEventsInRange(
base::Time::FromJavaTime(j_start), base::Time::FromJavaTime(j_end),
base::BindOnce(&UsageStatsBridge::OnGetEventsDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void UsageStatsBridge::AddEvents(JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const JavaRef<jobjectArray>& j_events,
const JavaRef<jobject>& j_callback) {
// Deserialize events from byte arrays to proto messages.
std::vector<std::string> serialized_events;
JavaArrayOfByteArrayToStringVector(j_env, j_events, &serialized_events);
std::vector<WebsiteEvent> events;
events.reserve(serialized_events.size());
for (const std::string& serialized : serialized_events) {
WebsiteEvent event;
event.ParseFromString(serialized);
events.emplace_back(event);
}
ScopedJavaGlobalRef<jobject> callback(j_callback);
usage_stats_database_->AddEvents(
events, base::BindOnce(&UsageStatsBridge::OnUpdateDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void UsageStatsBridge::DeleteAllEvents(JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const JavaRef<jobject>& j_callback) {
ScopedJavaGlobalRef<jobject> callback(j_callback);
usage_stats_database_->DeleteAllEvents(
base::BindOnce(&UsageStatsBridge::OnUpdateDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void UsageStatsBridge::DeleteEventsInRange(JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const jlong j_start,
const jlong j_end,
const JavaRef<jobject>& j_callback) {
ScopedJavaGlobalRef<jobject> callback(j_callback);
usage_stats_database_->DeleteEventsInRange(
base::Time::FromJavaTime(j_start), base::Time::FromJavaTime(j_end),
base::BindOnce(&UsageStatsBridge::OnUpdateDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void UsageStatsBridge::DeleteEventsWithMatchingDomains(
JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const JavaRef<jobjectArray>& j_domains,
const JavaRef<jobject>& j_callback) {
std::vector<std::string> domains;
AppendJavaStringArrayToStringVector(j_env, j_domains, &domains);
ScopedJavaGlobalRef<jobject> callback(j_callback);
usage_stats_database_->DeleteEventsWithMatchingDomains(
base::flat_set<std::string>(domains),
base::BindOnce(&UsageStatsBridge::OnUpdateDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void UsageStatsBridge::GetAllSuspensions(JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const JavaRef<jobject>& j_callback) {
ScopedJavaGlobalRef<jobject> callback(j_callback);
usage_stats_database_->GetAllSuspensions(
base::BindOnce(&UsageStatsBridge::OnGetAllSuspensionsDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void UsageStatsBridge::SetSuspensions(JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const JavaRef<jobjectArray>& j_domains,
const JavaRef<jobject>& j_callback) {
std::vector<std::string> domains;
AppendJavaStringArrayToStringVector(j_env, j_domains, &domains);
ScopedJavaGlobalRef<jobject> callback(j_callback);
usage_stats_database_->SetSuspensions(
domains, base::BindOnce(&UsageStatsBridge::OnUpdateDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void UsageStatsBridge::GetAllTokenMappings(JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const JavaRef<jobject>& j_callback) {
ScopedJavaGlobalRef<jobject> callback(j_callback);
usage_stats_database_->GetAllTokenMappings(
base::BindOnce(&UsageStatsBridge::OnGetAllTokenMappingsDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void UsageStatsBridge::SetTokenMappings(JNIEnv* j_env,
const JavaRef<jobject>& j_this,
const JavaRef<jobjectArray>& j_tokens,
const JavaRef<jobjectArray>& j_fqdns,
const JavaRef<jobject>& j_callback) {
ScopedJavaGlobalRef<jobject> callback(j_callback);
std::vector<std::string> tokens, fqdns;
AppendJavaStringArrayToStringVector(j_env, j_tokens, &tokens);
AppendJavaStringArrayToStringVector(j_env, j_fqdns, &fqdns);
DCHECK(tokens.size() == fqdns.size());
// Zip tokens (keys) and FQDNs (values) into a map.
UsageStatsDatabase::TokenMap mappings;
for (size_t i = 0; i < tokens.size(); i++) {
mappings.emplace(tokens[i], fqdns[i]);
}
usage_stats_database_->SetTokenMappings(
mappings, base::BindOnce(&UsageStatsBridge::OnUpdateDone,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void UsageStatsBridge::OnGetEventsDone(ScopedJavaGlobalRef<jobject> callback,
UsageStatsDatabase::Error error,
std::vector<WebsiteEvent> events) {
JNIEnv* env = AttachCurrentThread();
if (!isSuccess(error)) {
Java_UsageStatsBridge_createEventListAndRunCallback(
env, ToJavaArrayOfByteArray(env, std::vector<std::string>()), callback);
return;
}
// Serialize WebsiteEvent proto messages for passing over JNI bridge as byte
// arrays.
std::vector<std::string> serialized_events;
serialized_events.reserve(events.size());
for (WebsiteEvent event : events) {
std::string serialized;
event.SerializeToString(&serialized);
serialized_events.emplace_back(serialized);
}
ScopedJavaLocalRef<jobjectArray> j_serialized_events =
ToJavaArrayOfByteArray(env, serialized_events);
// Over JNI, deserialize to list of WebsiteEvent messages, and run on given
// callback.
Java_UsageStatsBridge_createEventListAndRunCallback(env, j_serialized_events,
callback);
}
void UsageStatsBridge::OnGetAllSuspensionsDone(
ScopedJavaGlobalRef<jobject> callback,
UsageStatsDatabase::Error error,
std::vector<std::string> suspensions) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobjectArray> j_suspensions =
isSuccess(error) ? ToJavaArrayOfStrings(env, suspensions)
: ToJavaArrayOfStrings(env, std::vector<std::string>());
RunObjectCallbackAndroid(callback, j_suspensions);
}
void UsageStatsBridge::OnGetAllTokenMappingsDone(
ScopedJavaGlobalRef<jobject> callback,
UsageStatsDatabase::Error error,
UsageStatsDatabase::TokenMap mappings) {
JNIEnv* env = AttachCurrentThread();
if (!isSuccess(error)) {
Java_UsageStatsBridge_createMapAndRunCallback(
env, ToJavaArrayOfStrings(env, std::vector<std::string>()),
ToJavaArrayOfStrings(env, std::vector<std::string>()), callback);
return;
}
// Create separate vectors of keys and values from map for passing over
// JNI bridge as String arrays.
std::vector<std::string> keys, values;
keys.reserve(mappings.size());
values.reserve(mappings.size());
for (auto mapping : mappings) {
keys.emplace_back(std::move(mapping.first));
values.emplace_back(std::move(mapping.second));
}
ScopedJavaLocalRef<jobjectArray> j_keys = ToJavaArrayOfStrings(env, keys);
ScopedJavaLocalRef<jobjectArray> j_values = ToJavaArrayOfStrings(env, values);
// Over JNI, reconstruct map from keys and values, and run on given callback.
Java_UsageStatsBridge_createMapAndRunCallback(env, j_keys, j_values,
callback);
}
void UsageStatsBridge::OnUpdateDone(ScopedJavaGlobalRef<jobject> callback,
UsageStatsDatabase::Error error) {
RunBooleanCallbackAndroid(callback, isSuccess(error));
}
// static
void UsageStatsBridge::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterBooleanPref(prefs::kUsageStatsEnabled, false);
}
void UsageStatsBridge::OnURLsDeleted(
history::HistoryService* history_service,
const history::DeletionInfo& deletion_info) {
// We ignore expirations since they're not user-initiated.
if (deletion_info.is_from_expiration()) {
return;
}
JNIEnv* env = AttachCurrentThread();
if (deletion_info.IsAllHistory()) {
Java_UsageStatsBridge_onAllHistoryDeleted(env, j_this_);
return;
}
history::DeletionTimeRange time_range = deletion_info.time_range();
if (time_range.IsValid()) {
int64_t startTimeMs = time_range.begin().ToJavaTime();
int64_t endTimeMs = time_range.end().ToJavaTime();
Java_UsageStatsBridge_onHistoryDeletedInRange(env, j_this_, startTimeMs,
endTimeMs);
return;
}
}
} // namespace usage_stats