Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 package org.chromium.content.app; | |
| 6 | |
| 7 import android.app.Service; | |
| 8 import android.content.Context; | |
| 9 import android.content.Intent; | |
| 10 import android.graphics.SurfaceTexture; | |
| 11 import android.os.Bundle; | |
| 12 import android.os.IBinder; | |
| 13 import android.os.ParcelFileDescriptor; | |
| 14 import android.os.Process; | |
| 15 import android.os.RemoteException; | |
| 16 import android.util.Log; | |
| 17 import android.view.Surface; | |
| 18 | |
| 19 import org.chromium.base.CalledByNative; | |
| 20 import org.chromium.content.app.ContentMain; | |
| 21 import org.chromium.content.browser.SandboxedProcessConnection; | |
| 22 import org.chromium.content.common.ISandboxedProcessCallback; | |
| 23 import org.chromium.content.common.ISandboxedProcessService; | |
| 24 import org.chromium.content.common.SurfaceCallback; | |
| 25 | |
| 26 /** | |
| 27 * This is the base class for sandboxed services; the SandboxedProcessService0, 1.. etc | |
| 28 * subclasses provide the concrete service entry points, to enable the browser t o connect | |
| 29 * to more than one distinct process (i.e. one process per service number, up to limit of N). | |
| 30 * The embedding application must declare these service instances in the applica tion section | |
| 31 * of its AndroidManifest.xml, for example with N entries of the form:- | |
| 32 * <service android:name="org.chromium.content.browser.SandboxedProcessServi ceX" | |
| 33 * android:process=":sandboxed_processX" /> | |
| 34 * for X in 0...N-1 (where N is {@link SandboxedProcessLauncher#MAX_REGISTERED_S ERVICES}) | |
| 35 */ | |
| 36 public class SandboxedProcessService extends Service { | |
| 37 private static final String MAIN_THREAD_NAME = "SandboxedProcessMain"; | |
| 38 private static final String TAG = "SandboxedProcessService"; | |
| 39 private ISandboxedProcessCallback mCallback; | |
| 40 | |
| 41 // This is the native "Main" thread for the renderer / utility process. | |
| 42 private Thread mSandboxMainThread; | |
| 43 // Parameters received via IPC, only accessed while holding the mSandboxMain Thread monitor. | |
| 44 private String[] mCommandLineParams; | |
| 45 private ParcelFileDescriptor mIPCFd; | |
| 46 private ParcelFileDescriptor mCrashFd; | |
| 47 private ParcelFileDescriptor mChromePakFd; | |
| 48 private ParcelFileDescriptor mLocalePakFd; | |
| 49 | |
| 50 private static Context sContext = null; | |
| 51 private boolean mLibraryInitialized = false; | |
| 52 | |
| 53 // Binder object used by clients for this service. | |
| 54 private final ISandboxedProcessService.Stub mBinder = new ISandboxedProcessS ervice.Stub() { | |
| 55 // NOTE: Implement any ISandboxedProcessService methods here. | |
| 56 @Override | |
| 57 public int setupConnection(Bundle args, ISandboxedProcessCallback callba ck) { | |
| 58 mCallback = callback; | |
| 59 synchronized (mSandboxMainThread) { | |
| 60 // Allow the command line to be set via bind() intent or setupCo nnection, but | |
| 61 // the FD can only be transferred here. | |
| 62 if (mCommandLineParams == null) { | |
| 63 mCommandLineParams = args.getStringArray( | |
| 64 SandboxedProcessConnection.EXTRA_COMMAND_LINE); | |
| 65 } | |
| 66 // We must have received the command line by now | |
| 67 assert mCommandLineParams != null; | |
| 68 mIPCFd = args.getParcelable(SandboxedProcessConnection.EXTRA_IPC _FD); | |
| 69 mChromePakFd = args.getParcelable(SandboxedProcessConnection.EXT RA_CHROME_PAK_FD); | |
|
Yaron
2012/06/11 19:46:22
Hmm. Not entirely sure how to fix this right now a
michaelbai
2012/06/11 20:30:16
Done.
Yaron
2012/06/11 20:45:51
So mLocalePakFd is part of the same problem. Pleas
| |
| 70 mLocalePakFd = args.getParcelable(SandboxedProcessConnection.EXT RA_LOCALE_PAK_FD); | |
| 71 // mCrashFd may be null if native crash reporting is disabled. | |
| 72 if (args.containsKey(SandboxedProcessConnection.EXTRA_CRASH_FD)) { | |
| 73 mCrashFd = args.getParcelable(SandboxedProcessConnection.EXT RA_CRASH_FD); | |
| 74 } | |
| 75 mSandboxMainThread.notifyAll(); | |
| 76 } | |
| 77 return Process.myPid(); | |
| 78 } | |
| 79 | |
| 80 @Override | |
| 81 public void setSurface(int type, Surface surface, int primaryID, int sec ondaryID) { | |
| 82 // This gives up ownership of the Surface. | |
| 83 SurfaceCallback.setSurface(type, surface, primaryID, secondaryID); | |
| 84 } | |
| 85 }; | |
| 86 | |
| 87 /* package */ static Context getContext() { | |
| 88 return sContext; | |
| 89 } | |
| 90 | |
| 91 @Override | |
| 92 public void onCreate() { | |
| 93 sContext = this; | |
| 94 super.onCreate(); | |
| 95 | |
| 96 mSandboxMainThread = new Thread(new Runnable() { | |
| 97 @Override | |
| 98 public void run() { | |
| 99 try { | |
| 100 // TODO(michaelbai): Upstream LibraryLoader.java | |
| 101 // if (!LibraryLoader.loadNow()) return; | |
| 102 synchronized (mSandboxMainThread) { | |
| 103 while (mCommandLineParams == null) { | |
| 104 mSandboxMainThread.wait(); | |
| 105 } | |
| 106 } | |
| 107 // LibraryLoader.initializeOnMainThread(mCommandLineParams); | |
| 108 synchronized (mSandboxMainThread) { | |
| 109 mLibraryInitialized = true; | |
| 110 mSandboxMainThread.notifyAll(); | |
| 111 while (mIPCFd == null) { | |
| 112 mSandboxMainThread.wait(); | |
| 113 } | |
| 114 } | |
| 115 int crashFd = (mCrashFd == null) ? -1 : mCrashFd.detachFd(); | |
| 116 ContentMain.initApplicationContext(sContext.getApplicationCo ntext()); | |
| 117 nativeInitSandboxedProcess(sContext.getApplicationContext(), | |
| 118 SandboxedProcessService.this, mIPCFd.detachFd(), cra shFd, | |
| 119 mChromePakFd.detachFd(), mLocalePakFd.detachFd()); | |
| 120 ContentMain.start(); | |
| 121 nativeExitSandboxedProcess(); | |
| 122 } catch (InterruptedException e) { | |
| 123 Log.w(TAG, MAIN_THREAD_NAME + " startup failed: " + e); | |
| 124 } | |
| 125 } | |
| 126 }, MAIN_THREAD_NAME); | |
| 127 mSandboxMainThread.start(); | |
| 128 } | |
| 129 | |
| 130 @Override | |
| 131 public void onDestroy() { | |
| 132 super.onDestroy(); | |
| 133 if (mCommandLineParams == null) { | |
| 134 // This process was destroyed before it even started. Nothing more t o do. | |
| 135 return; | |
| 136 } | |
| 137 synchronized (mSandboxMainThread) { | |
| 138 try { | |
| 139 while (!mLibraryInitialized) { | |
| 140 // Avoid a potential race in calling through to native code before the library | |
| 141 // has loaded. | |
| 142 mSandboxMainThread.wait(); | |
| 143 } | |
| 144 } catch (InterruptedException e) { | |
| 145 } | |
| 146 } | |
| 147 | |
| 148 // This is not synchronized with the main thread in any way, but this is analogous | |
| 149 // to how desktop chrome terminates processes using SIGTERM. The mSandbo xMainThread | |
| 150 // may run briefly before this is executed, but will eventually get a ch annel error | |
| 151 // and similarly commit suicide via SuicideOnChannelErrorFilter(). | |
| 152 // TODO(tedbo): Why doesn't the activity manager SIGTERM/SIGKILL this se rvice process? | |
| 153 nativeExitSandboxedProcess(); | |
| 154 } | |
| 155 | |
| 156 @Override | |
| 157 public IBinder onBind(Intent intent) { | |
| 158 // We call stopSelf() to request that this service be stopped as soon as the client | |
| 159 // unbinds. Otherwise the system may keep it around and available for a reconnect. The | |
| 160 // sandboxed processes do not currently support reconnect; they must be initialized from | |
| 161 // scratch every time. | |
| 162 stopSelf(); | |
| 163 | |
| 164 synchronized (mSandboxMainThread) { | |
| 165 mCommandLineParams = intent.getStringArrayExtra( | |
| 166 SandboxedProcessConnection.EXTRA_COMMAND_LINE); | |
| 167 mSandboxMainThread.notifyAll(); | |
| 168 } | |
| 169 | |
| 170 return mBinder; | |
| 171 } | |
| 172 | |
| 173 /** | |
| 174 * Called from native code to share a surface texture with another child pro cess. | |
| 175 * Through using the callback object the browser is used as a proxy to route the | |
| 176 * call to the correct process. | |
| 177 * | |
| 178 * @param pid Process handle of the sandboxed process to share the SurfaceTe xture with. | |
| 179 * @param type The type of process that the SurfaceTexture is for. | |
| 180 * @param surfaceObject The Surface or SurfaceTexture to share with the othe r sandboxed process. | |
| 181 * @param primaryID Used to route the call to the correct client instance. | |
| 182 * @param secondaryID Used to route the call to the correct client instance. | |
| 183 */ | |
| 184 @SuppressWarnings("unused") | |
| 185 @CalledByNative | |
| 186 private void establishSurfaceTexturePeer(int pid, int type, Object surfaceOb ject, int primaryID, | |
| 187 int secondaryID) { | |
| 188 if (mCallback == null) { | |
| 189 Log.e(TAG, "No callback interface has been provided."); | |
| 190 return; | |
| 191 } | |
| 192 | |
| 193 Surface surface = null; | |
| 194 boolean needRelease = false; | |
| 195 if (surfaceObject instanceof Surface) { | |
| 196 surface = (Surface)surfaceObject; | |
| 197 } else if (surfaceObject instanceof SurfaceTexture) { | |
| 198 surface = new Surface((SurfaceTexture)surfaceObject); | |
| 199 needRelease = true; | |
| 200 } else { | |
| 201 Log.e(TAG, "Not a valid surfaceObject: " + surfaceObject); | |
| 202 return; | |
| 203 } | |
| 204 try { | |
| 205 mCallback.establishSurfacePeer(pid, type, surface, primaryID, second aryID); | |
| 206 } catch (RemoteException e) { | |
| 207 Log.e(TAG, "Unable to call establishSurfaceTexturePeer: " + e); | |
| 208 return; | |
| 209 } finally { | |
| 210 if (needRelease) { | |
| 211 surface.release(); | |
| 212 } | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 /** | |
| 217 * The main entry point for a sandboxed process. This should be called from a new thread since | |
| 218 * it will not return until the sandboxed process exits. See sandboxed_proce ss_service.{h,cc} | |
| 219 * | |
| 220 * @param applicationContext The Application Context of the current process. | |
| 221 * @param service The current SandboxedProcessService object. | |
| 222 * @param ipcFd File descriptor to use for ipc. | |
| 223 * @param crashFd File descriptor for signaling crashes. | |
| 224 */ | |
| 225 private static native void nativeInitSandboxedProcess(Context applicationCon text, | |
| 226 SandboxedProcessService service, int ipcFd, int crashFd, int chromeP akFd, | |
| 227 int localePakFd); | |
| 228 | |
| 229 /** | |
| 230 * Force the sandboxed process to exit. | |
| 231 */ | |
| 232 private static native void nativeExitSandboxedProcess(); | |
| 233 } | |
| OLD | NEW |