blob: b2ba5857de15d88e0a188faa551dd46f54a2fa2e [file] [log] [blame]
// Copyright 2015 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 "components/gcm_driver/instance_id/instance_id_android.h"
#include <stdint.h>
#include <memory>
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "jni/InstanceIDBridge_jni.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertUTF8ToJavaString;
namespace instance_id {
InstanceIDAndroid::ScopedBlockOnAsyncTasksForTesting::
ScopedBlockOnAsyncTasksForTesting() {
JNIEnv* env = AttachCurrentThread();
previous_value_ =
Java_InstanceIDBridge_setBlockOnAsyncTasksForTesting(env, true);
}
InstanceIDAndroid::ScopedBlockOnAsyncTasksForTesting::
~ScopedBlockOnAsyncTasksForTesting() {
JNIEnv* env = AttachCurrentThread();
Java_InstanceIDBridge_setBlockOnAsyncTasksForTesting(env, previous_value_);
}
// static
std::unique_ptr<InstanceID> InstanceID::CreateInternal(
const std::string& app_id,
gcm::GCMDriver* gcm_driver) {
return std::make_unique<InstanceIDAndroid>(app_id, gcm_driver);
}
InstanceIDAndroid::InstanceIDAndroid(const std::string& app_id,
gcm::GCMDriver* gcm_driver)
: InstanceID(app_id, gcm_driver) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!app_id.empty()) << "Empty app_id is not supported";
// The |app_id| is stored in GCM's category field by the desktop InstanceID
// implementation, but because the category is reserved for the app's package
// name on Android the subtype field is used instead.
std::string subtype = app_id;
JNIEnv* env = AttachCurrentThread();
java_ref_.Reset(
Java_InstanceIDBridge_create(env, reinterpret_cast<intptr_t>(this),
ConvertUTF8ToJavaString(env, subtype)));
}
InstanceIDAndroid::~InstanceIDAndroid() {
DCHECK(thread_checker_.CalledOnValidThread());
JNIEnv* env = AttachCurrentThread();
Java_InstanceIDBridge_destroy(env, java_ref_);
}
void InstanceIDAndroid::GetID(const GetIDCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
int32_t request_id =
get_id_callbacks_.Add(std::make_unique<GetIDCallback>(callback));
JNIEnv* env = AttachCurrentThread();
Java_InstanceIDBridge_getId(env, java_ref_, request_id);
}
void InstanceIDAndroid::GetCreationTime(
const GetCreationTimeCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
int32_t request_id = get_creation_time_callbacks_.Add(
std::make_unique<GetCreationTimeCallback>(callback));
JNIEnv* env = AttachCurrentThread();
Java_InstanceIDBridge_getCreationTime(env, java_ref_, request_id);
}
void InstanceIDAndroid::GetToken(
const std::string& authorized_entity,
const std::string& scope,
const std::map<std::string, std::string>& options,
bool is_lazy,
GetTokenCallback callback) {
DCHECK(thread_checker_.CalledOnValidThread());
UMA_HISTOGRAM_COUNTS_100("InstanceID.GetToken.OptionsCount", options.size());
int32_t request_id = get_token_callbacks_.Add(
std::make_unique<GetTokenCallback>(std::move(callback)));
std::vector<std::string> options_strings;
for (const auto& entry : options) {
options_strings.push_back(entry.first);
options_strings.push_back(entry.second);
}
JNIEnv* env = AttachCurrentThread();
Java_InstanceIDBridge_getToken(
env, java_ref_, request_id,
ConvertUTF8ToJavaString(env, authorized_entity),
ConvertUTF8ToJavaString(env, scope),
base::android::ToJavaArrayOfStrings(env, options_strings), is_lazy);
}
void InstanceIDAndroid::ValidateToken(const std::string& authorized_entity,
const std::string& scope,
const std::string& token,
const ValidateTokenCallback& callback) {
// gcm_driver doesn't store tokens on Android, so assume it's valid.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(callback, true /* is_valid */));
}
void InstanceIDAndroid::DeleteTokenImpl(const std::string& authorized_entity,
const std::string& scope,
DeleteTokenCallback callback) {
DCHECK(thread_checker_.CalledOnValidThread());
int32_t request_id = delete_token_callbacks_.Add(
std::make_unique<DeleteTokenCallback>(std::move(callback)));
JNIEnv* env = AttachCurrentThread();
Java_InstanceIDBridge_deleteToken(
env, java_ref_, request_id,
ConvertUTF8ToJavaString(env, authorized_entity),
ConvertUTF8ToJavaString(env, scope));
}
void InstanceIDAndroid::DeleteIDImpl(DeleteIDCallback callback) {
DCHECK(thread_checker_.CalledOnValidThread());
int32_t request_id = delete_id_callbacks_.Add(
std::make_unique<DeleteIDCallback>(std::move(callback)));
JNIEnv* env = AttachCurrentThread();
Java_InstanceIDBridge_deleteInstanceID(env, java_ref_, request_id);
}
void InstanceIDAndroid::DidGetID(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
jint request_id,
const base::android::JavaParamRef<jstring>& jid) {
DCHECK(thread_checker_.CalledOnValidThread());
GetIDCallback* callback = get_id_callbacks_.Lookup(request_id);
DCHECK(callback);
callback->Run(ConvertJavaStringToUTF8(jid));
get_id_callbacks_.Remove(request_id);
}
void InstanceIDAndroid::DidGetCreationTime(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
jint request_id,
jlong creation_time_unix_ms) {
DCHECK(thread_checker_.CalledOnValidThread());
base::Time creation_time;
// If the InstanceID's getId, getToken and deleteToken methods have never been
// called, or deleteInstanceID has cleared it since, creation time will be 0.
if (creation_time_unix_ms) {
creation_time = base::Time::UnixEpoch() +
base::TimeDelta::FromMilliseconds(creation_time_unix_ms);
}
GetCreationTimeCallback* callback =
get_creation_time_callbacks_.Lookup(request_id);
DCHECK(callback);
callback->Run(creation_time);
get_creation_time_callbacks_.Remove(request_id);
}
void InstanceIDAndroid::DidGetToken(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
jint request_id,
const base::android::JavaParamRef<jstring>& jtoken) {
DCHECK(thread_checker_.CalledOnValidThread());
GetTokenCallback* callback = get_token_callbacks_.Lookup(request_id);
DCHECK(callback);
std::string token = ConvertJavaStringToUTF8(jtoken);
std::move(*callback).Run(
token, token.empty() ? InstanceID::UNKNOWN_ERROR : InstanceID::SUCCESS);
get_token_callbacks_.Remove(request_id);
}
void InstanceIDAndroid::DidDeleteToken(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
jint request_id,
jboolean success) {
DCHECK(thread_checker_.CalledOnValidThread());
DeleteTokenCallback* callback = delete_token_callbacks_.Lookup(request_id);
DCHECK(callback);
std::move(*callback).Run(success ? InstanceID::SUCCESS
: InstanceID::UNKNOWN_ERROR);
delete_token_callbacks_.Remove(request_id);
}
void InstanceIDAndroid::DidDeleteID(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
jint request_id,
jboolean success) {
DCHECK(thread_checker_.CalledOnValidThread());
DeleteIDCallback* callback = delete_id_callbacks_.Lookup(request_id);
DCHECK(callback);
std::move(*callback).Run(success ? InstanceID::SUCCESS
: InstanceID::UNKNOWN_ERROR);
delete_id_callbacks_.Remove(request_id);
}
} // namespace instance_id