blob: bbd20d30225a15550136c90b804338c5f5a01e8a [file] [log] [blame]
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -07001/*
Kevin Hartc0b94fa2015-09-07 15:13:57 +02002 * Copyright (c) 2014 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
Dave Tharpff9821f2015-06-29 10:32:40 -070042import com.android.browser.mdm.DevToolsRestriction;
43
Tarun Nainania1d74d62015-01-07 12:40:09 -080044import org.codeaurora.swe.BrowserCommandLine;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070045import org.codeaurora.swe.Engine;
46
47import java.util.ArrayList;
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -070048import java.util.HashMap;
49import java.util.Map;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070050import java.util.concurrent.CancellationException;
51import java.util.concurrent.ExecutionException;
52
Vivek Sekhared791da2015-02-22 12:39:05 -080053import org.chromium.base.VisibleForTesting;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070054
55public class EngineInitializer {
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -070056
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070057 private final static String LOGTAG = "EngineInitializer";
Kevin Harta3d001d2015-04-28 11:35:30 -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);
Tarun Nainanif03c7962015-06-03 11:38:33 -0700280 if (!BrowserCommandLine.hasSwitch(BrowserSwitches.SINGLE_PROCESS)) {
Kevin Harta3d001d2015-04-28 11:35:30 -0700281 Engine.warmUpChildProcess(mApplicationContext);
282 }
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700283 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());
Vivek Sekharf7ce2fb2015-08-11 14:12:52 -0700323 Engine.initializeCommandLine(ctx, CommandLineManager.getCommandLineSwitches(ctx));
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700324 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) {
Vivek Sekharf7ce2fb2015-08-11 14:12:52 -0700359
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700360 // TODO: Evaluate the benefit of async Engine.initialize()
Vivek Sekharf7ce2fb2015-08-11 14:12:52 -0700361 Engine.initialize(ctx, CommandLineManager.getCommandLineSwitches(ctx));
Vivek Sekhardcf9d6b2014-12-01 15:08:37 -0800362 // Add the browser commandline options
363 BrowserConfig.getInstance(ctx).initCommandLineSwitches();
Tarun Nainania1d74d62015-01-07 12:40:09 -0800364
365 //Note: Only enable this for debugging.
Tarun Nainanif03c7962015-06-03 11:38:33 -0700366 if (BrowserCommandLine.hasSwitch(BrowserSwitches.STRICT_MODE)) {
Tarun Nainania1d74d62015-01-07 12:40:09 -0800367 Log.v(LOGTAG, "StrictMode enabled");
368 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
369 .detectDiskReads()
370 .detectDiskWrites()
371 .detectNetwork()
372 .penaltyLog()
373 .build());
374 StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
375 .detectLeakedSqlLiteObjects()
376 .detectLeakedClosableObjects()
377 .penaltyLog()
378 .penaltyDeath()
379 .build());
380 }
381
Dave Tharpff9821f2015-06-29 10:32:40 -0700382 //Enable remote debugging by default as long as MDM restriction is not enabled
383 Engine.setWebContentsDebuggingEnabled(!DevToolsRestriction.getInstance().isEnabled());
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700384 mInitializationCompleted = true;
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700385 mInitializationStarted = true;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700386 BrowserSettings.getInstance().onEngineInitializationComplete();
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700387 Engine.resumeTracing(ctx);
388
389 if (mActivitySchedulerMap != null) {
390 for (Map.Entry<BrowserActivity, ActivityScheduler> entry : mActivitySchedulerMap.entrySet()) {
391 entry.getValue().onEngineInitializationCompletion(mSynchronousInitialization);
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700392 }
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700393 mActivitySchedulerMap.clear();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700394 }
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700395 }
396 }
397
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700398 public static void initializeResourceExtractor(Context ctx) {
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700399 Engine.startExtractingResources(ctx);
400 }
401
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700402 public static void onPreDraw(BrowserActivity activity) {
403 activity.getScheduler().onPreDraw();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700404 }
405
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700406 public static void onActivityPause(BrowserActivity activity) {
407 activity.getScheduler().onActivityPause();
Tarun Nainanib4a173f2015-01-05 09:23:08 -0800408 }
409
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700410 public static void onActivityStop(BrowserActivity activity) {
411 activity.getScheduler().onActivityStop();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700412 }
413
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700414 public static void onActivityResume(BrowserActivity activity) {
415 activity.getScheduler().onActivityResume();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700416 }
417
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700418 public static void onActivityStart(BrowserActivity activity) {
419 activity.getScheduler().onActivityStart();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700420 }
421
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700422 public static void onActivityResult(BrowserActivity activity, int requestCode, int resultCode, Intent data) {
423 activity.getScheduler().onActivityResult(requestCode, resultCode, data);
424 }
425
426 public static void onNewIntent(BrowserActivity activity, Intent intent) {
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700427 activity.getScheduler().onNewIntent(intent);
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700428 }
429
Kulanthaivel Palanichamy60aac812015-05-13 20:54:15 -0700430 public static void onActivityDestroy(BrowserActivity activity) {
Kevin Hart4ad2edc2015-01-19 15:00:21 -0800431 Engine.releaseSpareChildProcess();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700432 }
Tarun Nainania1d74d62015-01-07 12:40:09 -0800433}