Home | History | Annotate | Download | only in jni
      1 // Copyright 2013 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 "remoting/client/jni/chromoting_jni_runtime.h"
      6 
      7 #include "base/android/base_jni_registrar.h"
      8 #include "base/android/jni_android.h"
      9 #include "base/memory/singleton.h"
     10 #include "base/synchronization/waitable_event.h"
     11 #include "media/base/yuv_convert.h"
     12 #include "net/android/net_jni_registrar.h"
     13 #include "remoting/base/url_request_context.h"
     14 
     15 // Class and package name of the Java class supporting the methods we call.
     16 const char* const kJavaClass = "org/chromium/chromoting/jni/JniInterface";
     17 
     18 namespace remoting {
     19 
     20 // static
     21 ChromotingJniRuntime* ChromotingJniRuntime::GetInstance() {
     22   return Singleton<ChromotingJniRuntime>::get();
     23 }
     24 
     25 ChromotingJniRuntime::ChromotingJniRuntime() {
     26   // Obtain a reference to the Java environment. (Future calls to this function
     27   // made from the same thread return the same stored reference instead of
     28   // repeating the work of attaching to the JVM.)
     29   JNIEnv* env = base::android::AttachCurrentThread();
     30 
     31   // The base and networks stacks must be registered with JNI in order to work
     32   // on Android. An AtExitManager cleans this up at process exit.
     33   at_exit_manager_.reset(new base::AtExitManager());
     34   base::android::RegisterJni(env);
     35   net::android::RegisterJni(env);
     36 
     37   // On Android, the UI thread is managed by Java, so we need to attach and
     38   // start a special type of message loop to allow Chromium code to run tasks.
     39   LOG(INFO) << "Starting main message loop";
     40   ui_loop_.reset(new base::MessageLoopForUI());
     41   ui_loop_->Start();
     42 
     43   LOG(INFO) << "Spawning additional threads";
     44   // TODO(solb) Stop pretending to control the managed UI thread's lifetime.
     45   ui_task_runner_ = new AutoThreadTaskRunner(ui_loop_->message_loop_proxy(),
     46                                              base::MessageLoop::QuitClosure());
     47   network_task_runner_ = AutoThread::CreateWithType("native_net",
     48                                                     ui_task_runner_,
     49                                                     base::MessageLoop::TYPE_IO);
     50   display_task_runner_ = AutoThread::Create("native_disp",
     51                                             ui_task_runner_);
     52 
     53   url_requester_ = new URLRequestContextGetter(ui_task_runner_,
     54                                                network_task_runner_);
     55 
     56   // Allows later decoding of video frames.
     57   media::InitializeCPUSpecificYUVConversions();
     58 
     59   class_ = static_cast<jclass>(env->NewGlobalRef(env->FindClass(kJavaClass)));
     60 }
     61 
     62 ChromotingJniRuntime::~ChromotingJniRuntime() {
     63   // The singleton should only ever be destroyed on the main thread.
     64   DCHECK(ui_task_runner_->BelongsToCurrentThread());
     65 
     66   // The session must be shut down first, since it depends on our other
     67   // components' still being alive.
     68   DisconnectFromHost();
     69 
     70   JNIEnv* env = base::android::AttachCurrentThread();
     71   env->DeleteGlobalRef(class_);
     72 
     73   base::WaitableEvent done_event(false, false);
     74   network_task_runner_->PostTask(FROM_HERE, base::Bind(
     75       &ChromotingJniRuntime::DetachFromVmAndSignal,
     76       base::Unretained(this),
     77       &done_event));
     78   done_event.Wait();
     79   display_task_runner_->PostTask(FROM_HERE, base::Bind(
     80       &ChromotingJniRuntime::DetachFromVmAndSignal,
     81       base::Unretained(this),
     82       &done_event));
     83   done_event.Wait();
     84   base::android::DetachFromVM();
     85 }
     86 
     87 void ChromotingJniRuntime::ConnectToHost(const char* username,
     88                                   const char* auth_token,
     89                                   const char* host_jid,
     90                                   const char* host_id,
     91                                   const char* host_pubkey,
     92                                   const char* pairing_id,
     93                                   const char* pairing_secret) {
     94   DCHECK(ui_task_runner_->BelongsToCurrentThread());
     95   DCHECK(!session_);
     96   session_ = new ChromotingJniInstance(this,
     97                                        username,
     98                                        auth_token,
     99                                        host_jid,
    100                                        host_id,
    101                                        host_pubkey,
    102                                        pairing_id,
    103                                        pairing_secret);
    104 }
    105 
    106 void ChromotingJniRuntime::DisconnectFromHost() {
    107   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    108   if (session_) {
    109     session_->Cleanup();
    110     session_ = NULL;
    111   }
    112 }
    113 
    114 void ChromotingJniRuntime::ReportConnectionStatus(
    115     protocol::ConnectionToHost::State state,
    116     protocol::ErrorCode error) {
    117   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    118 
    119   JNIEnv* env = base::android::AttachCurrentThread();
    120   env->CallStaticVoidMethod(
    121     class_,
    122     env->GetStaticMethodID(class_, "reportConnectionStatus", "(II)V"),
    123     state,
    124     error);
    125 }
    126 
    127 void ChromotingJniRuntime::DisplayAuthenticationPrompt() {
    128   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    129 
    130   JNIEnv* env = base::android::AttachCurrentThread();
    131   env->CallStaticVoidMethod(
    132       class_,
    133       env->GetStaticMethodID(class_, "displayAuthenticationPrompt", "()V"));
    134 }
    135 
    136 void ChromotingJniRuntime::CommitPairingCredentials(const std::string& host,
    137                                                     const std::string& id,
    138                                                     const std::string& secret) {
    139   DCHECK(ui_task_runner_->BelongsToCurrentThread());
    140 
    141   JNIEnv* env = base::android::AttachCurrentThread();
    142   jstring host_jstr = env->NewStringUTF(host.c_str());
    143   jbyteArray id_arr = env->NewByteArray(id.size());
    144   env->SetByteArrayRegion(id_arr, 0, id.size(),
    145       reinterpret_cast<const jbyte*>(id.c_str()));
    146   jbyteArray secret_arr = env->NewByteArray(secret.size());
    147   env->SetByteArrayRegion(secret_arr, 0, secret.size(),
    148       reinterpret_cast<const jbyte*>(secret.c_str()));
    149 
    150   env->CallStaticVoidMethod(
    151       class_,
    152       env->GetStaticMethodID(
    153           class_,
    154           "commitPairingCredentials",
    155           "(Ljava/lang/String;[B[B)V"),
    156       host_jstr,
    157       id_arr,
    158       secret_arr);
    159 
    160   // Because we passed them as arguments, their corresponding Java objects were
    161   // GCd as soon as the managed method returned, so we mustn't release it here.
    162 }
    163 
    164 void ChromotingJniRuntime::UpdateImageBuffer(int width,
    165                                              int height,
    166                                              jobject buffer) {
    167   DCHECK(display_task_runner_->BelongsToCurrentThread());
    168 
    169   JNIEnv* env = base::android::AttachCurrentThread();
    170   env->SetStaticIntField(
    171       class_,
    172       env->GetStaticFieldID(class_, "sWidth", "I"),
    173       width);
    174   env->SetStaticIntField(
    175       class_,
    176       env->GetStaticFieldID(class_, "sHeight", "I"),
    177       height);
    178   env->SetStaticObjectField(
    179       class_,
    180       env->GetStaticFieldID(class_, "sBuffer", "Ljava/nio/ByteBuffer;"),
    181       buffer);
    182 }
    183 
    184 void ChromotingJniRuntime::RedrawCanvas() {
    185   DCHECK(display_task_runner_->BelongsToCurrentThread());
    186 
    187   JNIEnv* env = base::android::AttachCurrentThread();
    188   env->CallStaticVoidMethod(
    189       class_,
    190       env->GetStaticMethodID(class_, "redrawGraphicsInternal", "()V"));
    191 }
    192 
    193 void ChromotingJniRuntime::DetachFromVmAndSignal(base::WaitableEvent* waiter) {
    194   base::android::DetachFromVM();
    195   waiter->Signal();
    196 }
    197 
    198 }  // namespace remoting
    199