blob: ec4753cbdd11f14198781b5b1174dacbad818494 [file] [log] [blame]
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -07001/*
2 * Copyright (c) 2014 The Linux Foundation. All rights reserved.
3 *
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;
40
Tarun Nainania1d74d62015-01-07 12:40:09 -080041import org.codeaurora.swe.BrowserCommandLine;
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070042import org.codeaurora.swe.Engine;
43
44import java.util.ArrayList;
45import java.util.concurrent.CancellationException;
46import java.util.concurrent.ExecutionException;
47
48import com.google.common.annotations.VisibleForTesting;
49
50public class EngineInitializer {
51 private final static String LOGTAG = "EngineInitializer";
52
53 private BrowserActivity mActivity;
54
55 private boolean mNotifyActivity = false;
56 private boolean mActivityReady = false;
57 private boolean mActivityDestroyed = false;
58 private boolean mActivityStartPending = false;
59 private boolean mOnResumePending = false;
60
61 private boolean mFirstDrawCompleted = false;
62 private boolean mLibraryLoaded = false;
63 private boolean mInitializationCompleted = false;
64
65 private Handler mUiThreadHandler;
66
67 class ActivityResult
68 {
69 public Intent data;
70 public int requestCode;
71 public int resultCode;
72
73 public ActivityResult(int requestCode, int resultCode, Intent data)
74 {
75 this.requestCode = requestCode;
76 this.resultCode = resultCode;
77 this.data = data;
78 }
79 }
80 private ArrayList<ActivityResult> mPendingActivityResults = null;
81 private ArrayList<Intent> mPendingIntents = null;
82
83 private static EngineInitializer sEngineInitializer = null;
84 public static EngineInitializer getInstance() {
85 if (sEngineInitializer == null) {
86 sEngineInitializer = new EngineInitializer();
87 }
88 return sEngineInitializer;
89 }
90
91 private static long sDelayForTesting = 0;
92
Tarun Nainania1d74d62015-01-07 12:40:09 -080093 //Command line flag for strict mode
94 private static final String STRICT_MODE = "enable-strict-mode";
95
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -070096 @VisibleForTesting
97 public static void setDelayForTesting(long delay)
98 {
99 sDelayForTesting = delay;
100 }
101
102 private EngineInitializer() {
103 mUiThreadHandler = new Handler(Looper.getMainLooper());
104 }
105
106 @VisibleForTesting
107 public boolean isInitialized()
108 {
109 return mInitializationCompleted;
110 }
111
112 public boolean runningOnUiThread() {
113 return mUiThreadHandler.getLooper() == Looper.myLooper();
114 }
115
116 public void postOnUiThread(Runnable task) {
117 mUiThreadHandler.post(task);
118 }
119
120 private class InitializeTask extends AsyncTask<Void, Void, Boolean> {
121 public InitializeTask() {
122 }
123 @Override
124 protected Boolean doInBackground(Void... unused) {
125 try
126 {
127 // For testing.
128 if (sDelayForTesting > 0) {
129 Thread.sleep(sDelayForTesting);
130 }
131
132 Engine.loadNativeLibraries(mActivity.getApplicationContext());
133
134 Engine.warmUpChildProcess(mActivity.getApplicationContext());
135
136 return true;
137 }
138 catch (Exception e)
139 {
140 Log.e(LOGTAG, "Unable to load native library.", e);
141 }
142 return false;
143 }
144
145 @Override
146 protected void onPostExecute (Boolean result) {
147 mLibraryLoaded = true;
148 if (mFirstDrawCompleted) {
149 completeInitializationOnUiThread(mActivity.getApplicationContext());
150 }
151 }
152 }
153 private InitializeTask mInitializeTask = null;
154
155 public void initializeSync(Context ctx) {
156 assert runningOnUiThread() : "Tried to initialize the engine on the wrong thread.";
157
158 if (mInitializeTask != null) {
159 try {
160 // Wait for the InitializeTask to finish.
161 mInitializeTask.get();
162 } catch (CancellationException e1) {
163 Log.e(LOGTAG, "Native library load cancelled", e1);
164 } catch (ExecutionException e2) {
165 Log.e(LOGTAG, "Native library load failed", e2);
166 } catch (InterruptedException e3) {
167 Log.e(LOGTAG, "Native library load interrupted", e3);
168 }
169 }
170 completeInitializationOnUiThread(ctx);
171 }
172
173 private void reset(BrowserActivity newActivity) {
174 mActivity = newActivity;
175 mActivityStartPending = false;
176 mOnResumePending = false;
177 mNotifyActivity = true;
178 mActivityReady = false;
179 mPendingIntents = null;
180 mPendingActivityResults = null;
181 mFirstDrawCompleted = false;
182 mActivityDestroyed = false;
183 }
184
185 public void onActivityCreate(BrowserActivity activity) {
186 assert runningOnUiThread() : "Tried to initialize the engine on the wrong thread.";
187 reset(activity);
188 if (!mInitializationCompleted) {
189 Engine.initializeCommandLine(mActivity.getApplicationContext());
190 mInitializeTask = new InitializeTask();
191 mInitializeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
192 }
193 }
194
195 private void completeInitialization() {
196 postOnUiThread(new Runnable() {
197 @Override
198 public void run() {
199 completeInitializationOnUiThread(mActivity.getApplicationContext());
200 }
201 });
202 }
203
204 private void completeInitializationOnUiThread(Context ctx) {
205 assert runningOnUiThread() : "Tried to initialize the engine on the wrong thread.";
206
207 if (!mInitializationCompleted) {
208 // TODO: Evaluate the benefit of async Engine.initialize()
209 Engine.initialize(ctx);
Vivek Sekhardcf9d6b2014-12-01 15:08:37 -0800210 // Add the browser commandline options
211 BrowserConfig.getInstance(ctx).initCommandLineSwitches();
Tarun Nainania1d74d62015-01-07 12:40:09 -0800212
213 //Note: Only enable this for debugging.
214 if (BrowserCommandLine.hasSwitch(STRICT_MODE)) {
215 Log.v(LOGTAG, "StrictMode enabled");
216 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
217 .detectDiskReads()
218 .detectDiskWrites()
219 .detectNetwork()
220 .penaltyLog()
221 .build());
222 StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
223 .detectLeakedSqlLiteObjects()
224 .detectLeakedClosableObjects()
225 .penaltyLog()
226 .penaltyDeath()
227 .build());
228 }
229
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700230 //Enable remote debugging by default
231 Engine.setWebContentsDebuggingEnabled(true);
232 mInitializationCompleted = true;
233 mLibraryLoaded = true;
234 BrowserSettings.getInstance().onEngineInitializationComplete();
235 }
236 if (mActivity != null && mNotifyActivity) {
237 mNotifyActivity = false;
238 postOnUiThread(new Runnable() {
239 @Override
240 public void run() {
241 mActivity.onEngineInitializationComplete();
242 mActivityReady = true;
243 processPendingEvents();
244 }
245 });
246 }
247
248 }
249
250 private void processPendingEvents() {
251 assert runningOnUiThread() : "Tried to initialize the engine on the wrong thread.";
252
253 if (mActivityStartPending) {
254 mActivityStartPending = false;
255 onActivityStart();
256 }
257 if (mPendingIntents != null) {
258 for (int i = 0; i < mPendingIntents.size(); i++) {
259 mActivity.handleOnNewIntent(mPendingIntents.get(i));
260 }
261 mPendingIntents = null;
262 }
263 if (mPendingActivityResults != null) {
264 for (int i = 0; i < mPendingActivityResults.size(); i++) {
265 ActivityResult result = mPendingActivityResults.get(i);
266 mActivity.handleOnActivityResult(result.requestCode, result.resultCode, result.data);
267 }
268 mPendingActivityResults = null;
269 }
270 if (mOnResumePending && !mActivityDestroyed) {
271 onActivityResume();
272 }
273 mOnResumePending = false;
274 }
275
276 public void onPreDraw() {
277 mFirstDrawCompleted = true;
278 if (mLibraryLoaded) {
279 completeInitialization();
280 }
281 }
282
283 public void initializeResourceExtractor(Context ctx) {
284 Engine.startExtractingResources(ctx);
285 }
286
287 public void onActivityPause() {
288 mOnResumePending = false;
289 if (mActivityReady) {
Vivek Sekhar2868b8d2014-12-03 17:22:50 -0800290 mActivity.handleOnPause();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700291 }
292 }
293
Tarun Nainanib4a173f2015-01-05 09:23:08 -0800294 public void onActivityStop() {
295 mActivityStartPending = false;
296 if (mActivityReady) {
297 Engine.pauseTracing(mActivity.getApplicationContext());
298 mActivity.handleOnStop();
299 }
300 }
301
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700302 public void onActivityResume() {
303 if (mActivityReady) {
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700304 mActivity.handleOnResume();
305 return;
306 }
307 mOnResumePending = true;
308 }
309
310 public void onActivityStart() {
311 if (mActivityReady) {
Tarun Nainanib4a173f2015-01-05 09:23:08 -0800312 Engine.resumeTracing(mActivity.getApplicationContext());
313 mActivity.handleOnStart();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700314 // TODO: We have no reliable mechanism to know when the app goes background.
315 //ChildProcessLauncher.onBroughtToForeground();
316 return;
317 }
318 mActivityStartPending = true;
319 }
320
321 public void onActivityResult(int requestCode, int resultCode, Intent data) {
322 if (mActivityReady) {
323 mActivity.handleOnActivityResult(requestCode, resultCode, data);
324 return;
325 }
326 if (mPendingActivityResults == null) {
327 mPendingActivityResults = new ArrayList<ActivityResult>(1);
328 }
329 mPendingActivityResults.add(new ActivityResult(requestCode, resultCode, data));
330 }
331
332 public void onNewIntent(Intent intent) {
333 if (mActivityReady) {
334 mActivity.handleOnNewIntent(intent);
335 return;
336 }
337
338 if (mPendingIntents == null) {
339 mPendingIntents = new ArrayList<Intent>(1);
340 }
341 mPendingIntents.add(intent);
342 }
343
344 public void onActivityDestroy() {
345 mActivityDestroyed = true;
346 }
347
348
Tarun Nainania1d74d62015-01-07 12:40:09 -0800349}