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.
5 #include "content/browser/android/child_process_launcher_android.h"
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/frame_host/render_frame_host_impl.h"
12 #include "content/browser/media/android/browser_media_player_manager.h"
13 #include "content/browser/media/media_web_contents_observer.h"
14 #include "content/browser/renderer_host/compositor_impl_android.h"
15 #include "content/browser/web_contents/web_contents_impl.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/render_process_host.h"
18 #include "content/public/common/content_switches.h"
19 #include "jni/ChildProcessLauncher_jni.h"
20 #include "media/base/android/media_player_android.h"
21 #include "ui/gl/android/surface_texture.h"
23 using base::android::AttachCurrentThread
;
24 using base::android::ToJavaArrayOfStrings
;
25 using base::android::ScopedJavaGlobalRef
;
26 using base::android::ScopedJavaLocalRef
;
27 using content::StartChildProcessCallback
;
33 // Pass a java surface object to the MediaPlayerAndroid object
34 // identified by render process handle, render frame ID and player ID.
35 static void SetSurfacePeer(
36 const base::android::JavaRef
<jobject
>& surface
,
37 base::ProcessHandle render_process_handle
,
40 int render_process_id
= 0;
41 RenderProcessHost::iterator it
= RenderProcessHost::AllHostsIterator();
42 while (!it
.IsAtEnd()) {
43 if (it
.GetCurrentValue()->GetHandle() == render_process_handle
) {
44 render_process_id
= it
.GetCurrentValue()->GetID();
49 if (!render_process_id
) {
50 DVLOG(1) << "Cannot find render process for render_process_handle "
51 << render_process_handle
;
55 RenderFrameHostImpl
* frame
=
56 RenderFrameHostImpl::FromID(render_process_id
, render_frame_id
);
58 DVLOG(1) << "Cannot find frame for render_frame_id " << render_frame_id
;
62 WebContentsImpl
* web_contents
=
63 static_cast<WebContentsImpl
*>(WebContents::FromRenderFrameHost(frame
));
64 BrowserMediaPlayerManager
* player_manager
=
65 web_contents
->media_web_contents_observer()->GetMediaPlayerManager(frame
);
66 if (!player_manager
) {
67 DVLOG(1) << "Cannot find the media player manager for frame " << frame
;
71 media::MediaPlayerAndroid
* player
= player_manager
->GetPlayer(player_id
);
73 DVLOG(1) << "Cannot find media player for player_id " << player_id
;
77 if (player
!= player_manager
->GetFullscreenPlayer()) {
78 gfx::ScopedJavaSurface
scoped_surface(surface
);
79 player
->SetVideoSurface(scoped_surface
.Pass());
83 } // anonymous namespace
85 // Called from ChildProcessLauncher.java when the ChildProcess was
87 // |client_context| is the pointer to StartChildProcessCallback which was
88 // passed in from StartChildProcess.
89 // |handle| is the processID of the child process as originated in Java, 0 if
90 // the ChildProcess could not be created.
91 static void OnChildProcessStarted(JNIEnv
*,
95 StartChildProcessCallback
* callback
=
96 reinterpret_cast<StartChildProcessCallback
*>(client_context
);
98 callback
->Run(static_cast<base::ProcessHandle
>(handle
));
102 void StartChildProcess(
103 const base::CommandLine::StringVector
& argv
,
104 int child_process_id
,
105 scoped_ptr
<content::FileDescriptorInfo
> files_to_register
,
106 const StartChildProcessCallback
& callback
) {
107 JNIEnv
* env
= AttachCurrentThread();
110 // Create the Command line String[]
111 ScopedJavaLocalRef
<jobjectArray
> j_argv
= ToJavaArrayOfStrings(env
, argv
);
113 size_t file_count
= files_to_register
->GetMappingSize();
114 DCHECK(file_count
> 0);
116 ScopedJavaLocalRef
<jintArray
> j_file_ids(env
, env
->NewIntArray(file_count
));
117 base::android::CheckException(env
);
118 jint
* file_ids
= env
->GetIntArrayElements(j_file_ids
.obj(), NULL
);
119 base::android::CheckException(env
);
120 ScopedJavaLocalRef
<jintArray
> j_file_fds(env
, env
->NewIntArray(file_count
));
121 base::android::CheckException(env
);
122 jint
* file_fds
= env
->GetIntArrayElements(j_file_fds
.obj(), NULL
);
123 base::android::CheckException(env
);
124 ScopedJavaLocalRef
<jbooleanArray
> j_file_auto_close(
125 env
, env
->NewBooleanArray(file_count
));
126 base::android::CheckException(env
);
127 jboolean
* file_auto_close
=
128 env
->GetBooleanArrayElements(j_file_auto_close
.obj(), NULL
);
129 base::android::CheckException(env
);
130 for (size_t i
= 0; i
< file_count
; ++i
) {
131 // Owners of passed descriptors can outlive this function and we don't know
132 // when it is safe to close() them. So we pass dup()-ed FD and
133 // let ChildProcessLauncher in java take care of their lifetimes.
134 // TODO(morrita): Drop FileDescriptorInfo.mAutoClose on Java side.
135 file_auto_close
[i
] = true; // This indicates ownership transfer.
136 file_ids
[i
] = files_to_register
->GetIDAt(i
);
137 file_fds
[i
] = dup(files_to_register
->GetFDAt(i
));
138 PCHECK(0 <= file_fds
[i
]);
140 env
->ReleaseIntArrayElements(j_file_ids
.obj(), file_ids
, 0);
141 env
->ReleaseIntArrayElements(j_file_fds
.obj(), file_fds
, 0);
142 env
->ReleaseBooleanArrayElements(j_file_auto_close
.obj(), file_auto_close
, 0);
144 Java_ChildProcessLauncher_start(env
,
145 base::android::GetApplicationContext(),
150 j_file_auto_close
.obj(),
151 reinterpret_cast<intptr_t>(new StartChildProcessCallback(callback
)));
154 void StopChildProcess(base::ProcessHandle handle
) {
155 JNIEnv
* env
= AttachCurrentThread();
157 Java_ChildProcessLauncher_stop(env
, static_cast<jint
>(handle
));
160 bool IsChildProcessOomProtected(base::ProcessHandle handle
) {
161 JNIEnv
* env
= AttachCurrentThread();
163 return Java_ChildProcessLauncher_isOomProtected(env
,
164 static_cast<jint
>(handle
));
167 void SetChildProcessInForeground(base::ProcessHandle handle
,
168 bool in_foreground
) {
169 JNIEnv
* env
= AttachCurrentThread();
171 return Java_ChildProcessLauncher_setInForeground(env
,
172 static_cast<jint
>(handle
), static_cast<jboolean
>(in_foreground
));
175 void EstablishSurfacePeer(
176 JNIEnv
* env
, jclass clazz
,
177 jint pid
, jobject surface
, jint primary_id
, jint secondary_id
) {
178 ScopedJavaGlobalRef
<jobject
> jsurface
;
179 jsurface
.Reset(env
, surface
);
180 if (jsurface
.is_null())
183 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI
));
184 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, base::Bind(
185 &SetSurfacePeer
, jsurface
, pid
, primary_id
, secondary_id
));
188 void RegisterViewSurface(int surface_id
, jobject j_surface
) {
189 JNIEnv
* env
= AttachCurrentThread();
191 Java_ChildProcessLauncher_registerViewSurface(env
, surface_id
, j_surface
);
194 void UnregisterViewSurface(int surface_id
) {
195 JNIEnv
* env
= AttachCurrentThread();
197 Java_ChildProcessLauncher_unregisterViewSurface(env
, surface_id
);
200 void CreateSurfaceTextureSurface(int surface_texture_id
,
202 gfx::SurfaceTexture
* surface_texture
) {
203 JNIEnv
* env
= AttachCurrentThread();
205 Java_ChildProcessLauncher_createSurfaceTextureSurface(
209 surface_texture
->j_surface_texture().obj());
212 void DestroySurfaceTextureSurface(int surface_texture_id
, int client_id
) {
213 JNIEnv
* env
= AttachCurrentThread();
215 Java_ChildProcessLauncher_destroySurfaceTextureSurface(
216 env
, surface_texture_id
, client_id
);
219 gfx::ScopedJavaSurface
GetSurfaceTextureSurface(int surface_texture_id
,
221 JNIEnv
* env
= AttachCurrentThread();
223 return gfx::ScopedJavaSurface::AcquireExternalSurface(
224 Java_ChildProcessLauncher_getSurfaceTextureSurface(
225 env
, surface_texture_id
, client_id
).obj());
228 jboolean
IsSingleProcess(JNIEnv
* env
, jclass clazz
) {
229 return base::CommandLine::ForCurrentProcess()->HasSwitch(
230 switches::kSingleProcess
);
233 bool RegisterChildProcessLauncher(JNIEnv
* env
) {
234 return RegisterNativesImpl(env
);
237 } // namespace content