blob: 7a0c2364f7096ef89b712b3ee857a4e0c3874f55 [file] [log] [blame]
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -07001/*
Kevin Hart60a37f72015-02-09 17:14:14 -08002 * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -07003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31package com.android.browser;
32
33import android.content.Context;
34import android.content.Intent;
35import android.os.AsyncTask;
36import android.os.Handler;
37import android.os.Looper;
Tarun Nainania1d74d62015-01-07 12:40:09 -080038import android.os.StrictMode;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070039import android.util.Log;
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -070040import android.view.ViewTreeObserver;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070041
Tarun Nainania1d74d62015-01-07 12:40:09 -080042import org.codeaurora.swe.BrowserCommandLine;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070043import org.codeaurora.swe.Engine;
44
45import java.util.ArrayList;
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -070046import java.util.HashMap;
47import java.util.Map;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070048import java.util.concurrent.CancellationException;
49import java.util.concurrent.ExecutionException;
50
Vivek Sekhared791da2015-02-22 12:39:05 -080051import org.chromium.base.VisibleForTesting;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070052
53public class EngineInitializer {
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -070054
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070055 private final static String LOGTAG = "EngineInitializer";
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -070056 //Command line flag for strict mode
57 private final static String STRICT_MODE = "enable-strict-mode";
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070058
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -070059 private static boolean mInitializationStarted = false;
60 private static boolean mSynchronousInitialization = false;
61 private static boolean mInitializationCompleted = false;
62 private static Handler mUiThreadHandler;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070063
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -070064 static class ActivityResult
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070065 {
66 public Intent data;
67 public int requestCode;
68 public int resultCode;
69
70 public ActivityResult(int requestCode, int resultCode, Intent data)
71 {
72 this.requestCode = requestCode;
73 this.resultCode = resultCode;
74 this.data = data;
75 }
76 }
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070077
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -070078 public static class ActivityScheduler implements ViewTreeObserver.OnPreDrawListener
79 {
80 private BrowserActivity mActivity = null;
81 private ArrayList<ActivityResult> mPendingActivityResults = null;
82 private ArrayList<Intent> mPendingIntents = null;
83
84 private boolean mFirstDrawCompleted = false;
85 private boolean mOnStartPending = false;
86 private boolean mOnPausePending = false;
87 private boolean mEngineInitialized = false;
88 private boolean mCanForwardEvents = false;
89
90 public ActivityScheduler(BrowserActivity activity)
91 {
92 mActivity = activity;
93 mFirstDrawCompleted = false;
94 mOnStartPending = false;
95 mOnPausePending = false;
96 mPendingIntents = null;
97 mPendingActivityResults = null;
98 mEngineInitialized = false;
99 mCanForwardEvents = false;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700100 }
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700101
102 @VisibleForTesting
103 public boolean firstDrawCompleted() { return mFirstDrawCompleted; }
104 @VisibleForTesting
105 public boolean onStartPending() { return mOnStartPending; }
106 @VisibleForTesting
107 public boolean onPausePending() { return mOnPausePending; }
108 @VisibleForTesting
109 public boolean engineInitialized() { return mEngineInitialized; }
110 @VisibleForTesting
111 public boolean canForwardEvents() { return mCanForwardEvents; }
112
113 public void processPendingEvents() {
114 assert runningOnUiThread() : "Tried to initialize the engine on the wrong thread.";
115
116 if (mOnStartPending) {
117 mOnStartPending = false;
118 mActivity.handleOnStart();
119 }
120 if (mOnPausePending) {
121 mActivity.handleOnPause();
122 mOnPausePending = false;
123 }
124 if (mPendingIntents != null) {
125 for (int i = 0; i < mPendingIntents.size(); i++) {
126 mActivity.handleOnNewIntent(mPendingIntents.get(i));
127 }
128 mPendingIntents = null;
129 }
130 if (mPendingActivityResults != null) {
131 for (int i = 0; i < mPendingActivityResults.size(); i++) {
132 ActivityResult result = mPendingActivityResults.get(i);
133 mActivity.handleOnActivityResult(result.requestCode, result.resultCode, result.data);
134 }
135 mPendingActivityResults = null;
136 }
137 mCanForwardEvents = true;
138 }
139
140 public void onActivityCreate(boolean engineInitialized) {
141 mEngineInitialized = engineInitialized;
142 if (!mEngineInitialized) {
143 // Engine initialization is not completed, we should wait for the onPreDraw() notification.
144 final ViewTreeObserver observer = mActivity.getWindow().getDecorView().getViewTreeObserver();
145 observer.addOnPreDrawListener(this);
146 } else {
147 mFirstDrawCompleted = true;
148 mCanForwardEvents = true;
149 }
150 }
151
152 @Override
153 public boolean onPreDraw() {
154 final ViewTreeObserver observer = mActivity.getWindow().getDecorView().getViewTreeObserver();
155 observer.removeOnPreDrawListener(this);
156
157 if (mFirstDrawCompleted)
158 return true;
159
160 mFirstDrawCompleted = true;
161 if (mEngineInitialized) {
162 postOnUiThread(new Runnable() {
163 @Override
164 public void run() {
165 mActivity.startController();
166 processPendingEvents();
167 }
168 });
169 }
170 return true;
171 }
172
173 public void onEngineInitializationCompletion(boolean synchronous) {
174 if (synchronous) {
175 // Don't wait for pre-draw notification if it is synchronous
176 onPreDraw();
177 }
178 mEngineInitialized = true;
179 if (mFirstDrawCompleted) {
180 mActivity.startController();
181 processPendingEvents();
182 }
183 }
184
185 public void onActivityPause() {
186 if (mCanForwardEvents) {
187 mActivity.handleOnPause();
188 return;
189 }
190 mOnPausePending = true;
191 }
192
193 public void onActivityResume() {
194 if (mCanForwardEvents) {
195 mActivity.handleOnResume();
196 return;
197 }
198 mOnPausePending = false;
199 }
200
201 public void onActivityStart() {
202 if (mCanForwardEvents) {
203 mActivity.handleOnStart();
204 // TODO: We have no reliable mechanism to know when the app goes background.
205 //ChildProcessLauncher.onBroughtToForeground();
206 return;
207 }
208 mOnStartPending = true;
209 }
210
211 public void onActivityStop() {
212 if (!mCanForwardEvents) {
213 initializeSync(mActivity.getApplicationContext());
214 }
215 mActivity.handleOnStop();
216 }
217
218 public void onActivityResult(int requestCode, int resultCode, Intent data) {
219 if (mCanForwardEvents) {
220 mActivity.handleOnActivityResult(requestCode, resultCode, data);
221 return;
222 }
223 if (mPendingActivityResults == null) {
224 mPendingActivityResults = new ArrayList<ActivityResult>(1);
225 }
226 mPendingActivityResults.add(new ActivityResult(requestCode, resultCode, data));
227 }
228
229 public void onNewIntent(Intent intent) {
230 if (mCanForwardEvents) {
231 mActivity.handleOnNewIntent(intent);
232 return;
233 }
234
235 if (mPendingIntents == null) {
236 mPendingIntents = new ArrayList<Intent>(1);
237 }
238 mPendingIntents.add(intent);
239 }
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700240 }
241
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700242 private static HashMap<BrowserActivity, ActivityScheduler> mActivitySchedulerMap = null;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700243 private static long sDelayForTesting = 0;
244
245 @VisibleForTesting
246 public static void setDelayForTesting(long delay)
247 {
248 sDelayForTesting = delay;
249 }
250
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700251 @VisibleForTesting
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700252 public static boolean isInitialized()
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700253 {
254 return mInitializationCompleted;
255 }
256
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700257 public static boolean runningOnUiThread() {
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700258 return mUiThreadHandler.getLooper() == Looper.myLooper();
259 }
260
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700261 public static void postOnUiThread(Runnable task) {
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700262 mUiThreadHandler.post(task);
263 }
264
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700265 private static class InitializeTask extends AsyncTask<Void, Void, Boolean> {
266 private Context mApplicationContext;
267 public InitializeTask(Context ctx) {
268 mApplicationContext = ctx;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700269 }
270 @Override
271 protected Boolean doInBackground(Void... unused) {
272 try
273 {
274 // For testing.
275 if (sDelayForTesting > 0) {
276 Thread.sleep(sDelayForTesting);
277 }
278
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700279 Engine.loadNativeLibraries(mApplicationContext);
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700280
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700281 Engine.warmUpChildProcess(mApplicationContext);
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700282
283 return true;
284 }
285 catch (Exception e)
286 {
287 Log.e(LOGTAG, "Unable to load native library.", e);
288 }
289 return false;
290 }
291
292 @Override
293 protected void onPostExecute (Boolean result) {
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700294 completeInitializationOnUiThread(mApplicationContext);
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700295 }
296 }
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700297 private static InitializeTask mInitializeTask = null;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700298
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700299 public static void initializeSync(Context ctx) {
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700300 assert runningOnUiThread() : "Tried to initialize the engine on the wrong thread.";
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700301 mSynchronousInitialization = true;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700302 if (mInitializeTask != null) {
303 try {
304 // Wait for the InitializeTask to finish.
305 mInitializeTask.get();
306 } catch (CancellationException e1) {
307 Log.e(LOGTAG, "Native library load cancelled", e1);
308 } catch (ExecutionException e2) {
309 Log.e(LOGTAG, "Native library load failed", e2);
310 } catch (InterruptedException e3) {
311 Log.e(LOGTAG, "Native library load interrupted", e3);
312 }
313 }
314 completeInitializationOnUiThread(ctx);
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700315 mSynchronousInitialization = false;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700316 }
317
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700318 private static void initialize(Context ctx) {
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700319 if (!mInitializationCompleted) {
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700320 if (!mInitializationStarted) {
321 mInitializationStarted = true;
322 mUiThreadHandler = new Handler(Looper.getMainLooper());
323 Engine.initializeCommandLine(ctx);
324 mInitializeTask = new InitializeTask(ctx);
325 mInitializeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
326 mActivitySchedulerMap = new HashMap<BrowserActivity, ActivityScheduler>();
327 } else {
328 // This is not the first activity, wait for the engine initialization to finish.
329 initializeSync(ctx);
330 }
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700331 }
332 }
333
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700334 public static ActivityScheduler onActivityCreate(BrowserActivity activity) {
335 assert runningOnUiThread() : "Tried to initialize the engine on the wrong thread.";
336
337 Context ctx = activity.getApplicationContext();
338 ActivityScheduler scheduler = new ActivityScheduler(activity);
339 initialize(ctx);
340
341 scheduler.onActivityCreate(mInitializationCompleted);
342 if (!mInitializationCompleted) {
343 mActivitySchedulerMap.put(activity, scheduler);
344 }
345 return scheduler;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700346 }
347
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700348 public static void onPostActivityCreate(BrowserActivity activity) {
349 EngineInitializer.initializeResourceExtractor(activity);
350 if (EngineInitializer.isInitialized()) {
351 activity.startController();
352 }
353 }
354
355 private static void completeInitializationOnUiThread(Context ctx) {
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700356 assert runningOnUiThread() : "Tried to initialize the engine on the wrong thread.";
357
358 if (!mInitializationCompleted) {
359 // TODO: Evaluate the benefit of async Engine.initialize()
360 Engine.initialize(ctx);
Vivek Sekhardcf9d6b2014-12-01 15:08:37 -0800361 // Add the browser commandline options
362 BrowserConfig.getInstance(ctx).initCommandLineSwitches();
Tarun Nainania1d74d62015-01-07 12:40:09 -0800363
364 //Note: Only enable this for debugging.
365 if (BrowserCommandLine.hasSwitch(STRICT_MODE)) {
366 Log.v(LOGTAG, "StrictMode enabled");
367 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
368 .detectDiskReads()
369 .detectDiskWrites()
370 .detectNetwork()
371 .penaltyLog()
372 .build());
373 StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
374 .detectLeakedSqlLiteObjects()
375 .detectLeakedClosableObjects()
376 .penaltyLog()
377 .penaltyDeath()
378 .build());
379 }
380
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700381 //Enable remote debugging by default
382 Engine.setWebContentsDebuggingEnabled(true);
383 mInitializationCompleted = true;
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700384 mInitializationStarted = true;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700385 BrowserSettings.getInstance().onEngineInitializationComplete();
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700386 Engine.resumeTracing(ctx);
387
388 if (mActivitySchedulerMap != null) {
389 for (Map.Entry<BrowserActivity, ActivityScheduler> entry : mActivitySchedulerMap.entrySet()) {
390 entry.getValue().onEngineInitializationCompletion(mSynchronousInitialization);
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700391 }
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700392 mActivitySchedulerMap.clear();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700393 }
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700394 }
395 }
396
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700397 public static void initializeResourceExtractor(Context ctx) {
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700398 Engine.startExtractingResources(ctx);
399 }
400
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700401 public static void onPreDraw(BrowserActivity activity) {
402 activity.getScheduler().onPreDraw();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700403 }
404
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700405 public static void onActivityPause(BrowserActivity activity) {
406 activity.getScheduler().onActivityPause();
Tarun Nainanib4a173f2015-01-05 09:23:08 -0800407 }
408
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700409 public static void onActivityStop(BrowserActivity activity) {
410 activity.getScheduler().onActivityStop();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700411 }
412
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700413 public static void onActivityResume(BrowserActivity activity) {
414 activity.getScheduler().onActivityResume();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700415 }
416
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700417 public static void onActivityStart(BrowserActivity activity) {
418 activity.getScheduler().onActivityStart();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700419 }
420
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700421 public static void onActivityResult(BrowserActivity activity, int requestCode, int resultCode, Intent data) {
422 activity.getScheduler().onActivityResult(requestCode, resultCode, data);
423 }
424
425 public static void onNewIntent(BrowserActivity activity, Intent intent) {
Kevin Hart60a37f72015-02-09 17:14:14 -0800426 if (BrowserActivity.ACTION_RESTART.equals(intent.getAction())) {
427 Engine.releaseSpareChildProcess();
428 }
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700429 activity.getScheduler().onNewIntent(intent);
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700430 }
431
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700432 public static void onActivityDestroy(BrowserActivity activity) {
Kevin Hart4ad2edc2015-01-19 15:00:21 -0800433 Engine.releaseSpareChildProcess();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700434 }
Tarun Nainania1d74d62015-01-07 12:40:09 -0800435}