| // 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 |