Home | History | Annotate | Download | only in android
      1 // Copyright (c) 2012 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 "content/browser/android/child_process_launcher_android.h"
      6 
      7 #include "base/android/jni_android.h"
      8 #include "base/android/jni_array.h"
      9 #include "base/logging.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "content/browser/media/android/browser_media_player_manager.h"
     12 #include "content/browser/renderer_host/compositor_impl_android.h"
     13 #include "content/browser/renderer_host/render_view_host_impl.h"
     14 #include "content/public/browser/browser_thread.h"
     15 #include "content/public/browser/render_process_host.h"
     16 #include "content/public/common/content_switches.h"
     17 #include "jni/ChildProcessLauncher_jni.h"
     18 #include "media/base/android/media_player_android.h"
     19 #include "ui/gl/android/scoped_java_surface.h"
     20 
     21 using base::android::AttachCurrentThread;
     22 using base::android::ToJavaArrayOfStrings;
     23 using base::android::ScopedJavaGlobalRef;
     24 using base::android::ScopedJavaLocalRef;
     25 using content::StartChildProcessCallback;
     26 
     27 namespace content {
     28 
     29 namespace {
     30 
     31 // Pass a java surface object to the MediaPlayerAndroid object
     32 // identified by render process handle, render view ID and player ID.
     33 static void SetSurfacePeer(
     34     const base::android::JavaRef<jobject>& surface,
     35     base::ProcessHandle render_process_handle,
     36     int render_view_id,
     37     int player_id) {
     38   int renderer_id = 0;
     39   RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
     40   while (!it.IsAtEnd()) {
     41     if (it.GetCurrentValue()->GetHandle() == render_process_handle) {
     42       renderer_id = it.GetCurrentValue()->GetID();
     43       break;
     44     }
     45     it.Advance();
     46   }
     47 
     48   if (renderer_id) {
     49     RenderViewHostImpl* host = RenderViewHostImpl::FromID(
     50         renderer_id, render_view_id);
     51     if (host) {
     52       media::MediaPlayerAndroid* player =
     53           host->media_player_manager()->GetPlayer(player_id);
     54       if (player &&
     55           player != host->media_player_manager()->GetFullscreenPlayer()) {
     56         gfx::ScopedJavaSurface scoped_surface(surface);
     57         player->SetVideoSurface(scoped_surface.Pass());
     58       }
     59     }
     60   }
     61 }
     62 
     63 }  // anonymous namespace
     64 
     65 // Called from ChildProcessLauncher.java when the ChildProcess was
     66 // started.
     67 // |client_context| is the pointer to StartChildProcessCallback which was
     68 // passed in from StartChildProcess.
     69 // |handle| is the processID of the child process as originated in Java, 0 if
     70 // the ChildProcess could not be created.
     71 static void OnChildProcessStarted(JNIEnv*,
     72                                   jclass,
     73                                   jlong client_context,
     74                                   jint handle) {
     75   StartChildProcessCallback* callback =
     76       reinterpret_cast<StartChildProcessCallback*>(client_context);
     77   if (handle)
     78     callback->Run(static_cast<base::ProcessHandle>(handle));
     79   delete callback;
     80 }
     81 
     82 void StartChildProcess(
     83     const CommandLine::StringVector& argv,
     84     const std::vector<content::FileDescriptorInfo>& files_to_register,
     85     const StartChildProcessCallback& callback) {
     86   JNIEnv* env = AttachCurrentThread();
     87   DCHECK(env);
     88 
     89   // Create the Command line String[]
     90   ScopedJavaLocalRef<jobjectArray> j_argv = ToJavaArrayOfStrings(env, argv);
     91 
     92   size_t file_count = files_to_register.size();
     93   DCHECK(file_count > 0);
     94 
     95   ScopedJavaLocalRef<jintArray> j_file_ids(env, env->NewIntArray(file_count));
     96   base::android::CheckException(env);
     97   jint* file_ids = env->GetIntArrayElements(j_file_ids.obj(), NULL);
     98   base::android::CheckException(env);
     99   ScopedJavaLocalRef<jintArray> j_file_fds(env, env->NewIntArray(file_count));
    100   base::android::CheckException(env);
    101   jint* file_fds = env->GetIntArrayElements(j_file_fds.obj(), NULL);
    102   base::android::CheckException(env);
    103   ScopedJavaLocalRef<jbooleanArray> j_file_auto_close(
    104       env, env->NewBooleanArray(file_count));
    105   base::android::CheckException(env);
    106   jboolean* file_auto_close =
    107       env->GetBooleanArrayElements(j_file_auto_close.obj(), NULL);
    108   base::android::CheckException(env);
    109   for (size_t i = 0; i < file_count; ++i) {
    110     const content::FileDescriptorInfo& fd_info = files_to_register[i];
    111     file_ids[i] = fd_info.id;
    112     file_fds[i] = fd_info.fd.fd;
    113     file_auto_close[i] = fd_info.fd.auto_close;
    114   }
    115   env->ReleaseIntArrayElements(j_file_ids.obj(), file_ids, 0);
    116   env->ReleaseIntArrayElements(j_file_fds.obj(), file_fds, 0);
    117   env->ReleaseBooleanArrayElements(j_file_auto_close.obj(), file_auto_close, 0);
    118 
    119   Java_ChildProcessLauncher_start(env,
    120       base::android::GetApplicationContext(),
    121       j_argv.obj(),
    122       j_file_ids.obj(),
    123       j_file_fds.obj(),
    124       j_file_auto_close.obj(),
    125       reinterpret_cast<intptr_t>(new StartChildProcessCallback(callback)));
    126 }
    127 
    128 void StopChildProcess(base::ProcessHandle handle) {
    129   JNIEnv* env = AttachCurrentThread();
    130   DCHECK(env);
    131   Java_ChildProcessLauncher_stop(env, static_cast<jint>(handle));
    132 }
    133 
    134 bool IsChildProcessOomProtected(base::ProcessHandle handle) {
    135   JNIEnv* env = AttachCurrentThread();
    136   DCHECK(env);
    137   return Java_ChildProcessLauncher_isOomProtected(env,
    138       static_cast<jint>(handle));
    139 }
    140 
    141 void EstablishSurfacePeer(
    142     JNIEnv* env, jclass clazz,
    143     jint pid, jobject surface, jint primary_id, jint secondary_id) {
    144   ScopedJavaGlobalRef<jobject> jsurface;
    145   jsurface.Reset(env, surface);
    146   if (jsurface.is_null())
    147     return;
    148 
    149   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
    150   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
    151       &SetSurfacePeer, jsurface, pid, primary_id, secondary_id));
    152 }
    153 
    154 jobject GetViewSurface(JNIEnv* env, jclass clazz, jint surface_id) {
    155   // This is a synchronous call from the GPU process and is expected to be
    156   // handled on a binder thread. Handling this on the UI thread will lead
    157   // to deadlocks.
    158   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
    159   return CompositorImpl::GetSurface(surface_id);
    160 }
    161 
    162 jboolean IsSingleProcess(JNIEnv* env, jclass clazz) {
    163   return CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
    164 }
    165 
    166 bool RegisterChildProcessLauncher(JNIEnv* env) {
    167   return RegisterNativesImpl(env);
    168 }
    169 
    170 }  // namespace content
    171