1 // Copyright (c) 2013 Intel Corporation. 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 package org.xwalk.core.internal;
7 import java.io.BufferedReader;
8 import java.io.InputStream;
9 import java.io.InputStreamReader;
10 import java.io.IOException;
11 import java.lang.StringBuilder;
12 import java.util.HashSet;
15 import android.content.Context;
16 import android.content.res.AssetManager;
17 import android.content.res.Resources.NotFoundException;
18 import android.os.Build;
19 import android.util.Log;
21 import org.chromium.base.ApplicationStatusManager;
22 import org.chromium.base.CommandLine;
23 import org.chromium.base.JNINamespace;
24 import org.chromium.base.PathUtils;
25 import org.chromium.base.ThreadUtils;
26 import org.chromium.base.library_loader.LibraryLoader;
27 import org.chromium.base.library_loader.ProcessInitException;
28 import org.chromium.content.browser.BrowserStartupController;
29 import org.chromium.content.browser.DeviceUtils;
30 import org.chromium.content.browser.ResourceExtractor;
31 import org.chromium.content.browser.ResourceExtractor.ResourceIntercepter;
32 import org.chromium.net.NetworkChangeNotifier;
34 @JNINamespace("xwalk")
35 class XWalkViewDelegate {
36 private static boolean sInitialized = false;
37 private static boolean sLibraryLoaded = false;
38 private static boolean sRunningOnIA = true;
39 private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "xwalkcore";
40 private static final String[] MANDATORY_PAKS = {
45 private static final String[] MANDATORY_LIBRARIES = {
48 private static final String TAG = "XWalkViewDelegate";
49 private static final String XWALK_RESOURCES_LIST_RES_NAME = "xwalk_resources_list";
51 private static final String COMMAND_LINE_FILE = "xwalk-command-line";
53 private static String[] readCommandLine(Context context) {
54 InputStreamReader reader = null;
58 context.getAssets().open(COMMAND_LINE_FILE, AssetManager.ACCESS_BUFFER);
61 char[] buffer = new char[size];
62 StringBuilder builder = new StringBuilder();
64 reader = new InputStreamReader(input, "UTF-8");
65 while ((length = reader.read(buffer, 0, size)) != -1) {
66 builder.append(buffer, 0, length);
69 return CommandLine.tokenizeQuotedAruments(
70 builder.toString().toCharArray());
71 } catch (IOException e) {
75 if (reader != null) reader.close();
76 } catch (IOException e) {
77 Log.e(TAG, "Unable to close file reader.", e);
82 public static void loadXWalkLibrary(Context context) throws UnsatisfiedLinkError {
83 if (sLibraryLoaded) return;
85 // If context is null, it's called from wrapper's ReflectionHelper to try
86 // loading native library within the package. No need to try load from library
87 // package in this case.
88 // If context's applicationContext is not the same package with itself,
89 // It's a cross package invoking, load core library from library apk.
90 // Only load the native library from /data/data if the Android version is
91 // lower than 4.2. Android enables a system path /data/app-lib to store native
92 // libraries starting from 4.2 and load them automatically.
93 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 && context != null &&
94 !context.getApplicationContext().getPackageName().equals(context.getPackageName())) {
95 for (String library : MANDATORY_LIBRARIES) {
96 System.load("/data/data/" + context.getPackageName() + "/lib/" + library);
101 if (sRunningOnIA && !nativeIsLibraryBuiltForIA()) {
102 throw new UnsatisfiedLinkError();
104 sLibraryLoaded = true;
107 public static void init(XWalkViewInternal xwalkView) throws UnsatisfiedLinkError {
112 loadXWalkLibrary(xwalkView.getContext());
114 // Initialize the ActivityStatus. This is needed and used by many internal
115 // features such as location provider to listen to activity status.
116 ApplicationStatusManager.init(xwalkView.getActivity().getApplication());
118 // Auto detect network connectivity state.
119 // setAutoDetectConnectivityState() need to be called before activity started.
120 NetworkChangeNotifier.init(xwalkView.getActivity());
121 NetworkChangeNotifier.setAutoDetectConnectivityState(true);
123 // We will miss activity onCreate() status in ApplicationStatusManager,
124 // informActivityStarted() will simulate these callbacks.
125 ApplicationStatusManager.informActivityStarted(xwalkView.getActivity());
127 final Context context = xwalkView.getViewContext();
129 // Last place to initialize CommandLine object. If you haven't initialize
130 // the CommandLine object before XWalkViewContent is created, here will create
131 // the object to guarantee the CommandLine object is not null and the
132 // consequent prodedure does not crash.
133 if (!CommandLine.isInitialized()) {
134 CommandLine.init(readCommandLine(context.getApplicationContext()));
137 ResourceExtractor.setMandatoryPaksToExtract(MANDATORY_PAKS);
138 final int resourcesListResId = context.getResources().getIdentifier(
139 XWALK_RESOURCES_LIST_RES_NAME, "array", context.getPackageName());
140 final AssetManager assets = context.getAssets();
141 if (!context.getPackageName().equals(context.getApplicationContext().getPackageName()) ||
142 resourcesListResId != 0) {
143 // For shared mode, assets are in library package.
144 // For embedding API usage, assets are in res/raw.
145 ResourceExtractor.setResourceIntercepter(new ResourceIntercepter() {
148 public Set<String> getInterceptableResourceList() {
149 Set<String> resourcesList = new HashSet<String>();
150 if (!context.getPackageName().equals(
151 context.getApplicationContext().getPackageName())) {
153 for (String resource : assets.list("")) {
154 resourcesList.add(resource);
156 } catch (IOException e){}
158 if (resourcesListResId != 0) {
160 String[] resources = context.getResources().getStringArray(resourcesListResId);
161 for (String resource : resources) {
162 resourcesList.add(resource);
164 } catch (NotFoundException e) {
165 Log.w(TAG, "R.array." + XWALK_RESOURCES_LIST_RES_NAME + " can't be found.");
168 return resourcesList;
172 public InputStream interceptLoadingForResource(String resource) {
173 if (!context.getPackageName().equals(
174 context.getApplicationContext().getPackageName())) {
176 InputStream fromAsset = context.getAssets().open(resource);
177 if (fromAsset != null) return fromAsset;
178 } catch (IOException e) {
179 Log.w(TAG, resource + " can't be found in assets.");
183 if (resourcesListResId != 0) {
184 String resourceName = resource.split("\\.")[0];
185 int resId = context.getResources().getIdentifier(
186 resourceName, "raw", context.getPackageName());
188 if (resId != 0) return context.getResources().openRawResource(resId);
189 } catch (NotFoundException e) {
190 Log.w(TAG, "R.raw." + resourceName + " can't be found.");
198 ResourceExtractor.setExtractImplicitLocaleForTesting(false);
199 // Use MixedContext to initialize the ResourceExtractor, as the pak file
200 // is in the library apk if in shared apk mode.
201 ResourceExtractor.get(context);
203 startBrowserProcess(context);
207 private static void loadLibrary(Context context) {
208 PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
210 LibraryLoader.loadNow(context, true);
211 } catch (ProcessInitException e) {
212 throw new RuntimeException("Cannot load Crosswalk Core", e);
216 private static void startBrowserProcess(final Context context) {
217 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
221 LibraryLoader.ensureInitialized();
222 } catch (ProcessInitException e) {
223 throw new RuntimeException("Cannot initialize Crosswalk Core", e);
225 DeviceUtils.addDeviceSpecificUserAgentSwitch(context);
226 CommandLine.getInstance().appendSwitchWithValue(
227 XWalkSwitches.PROFILE_NAME,
228 XWalkPreferencesInternal.getStringValue(XWalkPreferencesInternal.PROFILE_NAME));
230 BrowserStartupController.get(context).startBrowserProcessesSync(
232 } catch (ProcessInitException e) {
233 throw new RuntimeException("Cannot initialize Crosswalk Core", e);
239 public static boolean isRunningOnIA() {
243 private static native boolean nativeIsLibraryBuiltForIA();
246 sRunningOnIA = Build.CPU_ABI.equalsIgnoreCase("x86");
248 // This is not the final decision yet.
249 // With latest Houdini, an app with ARM binary will see system abi as if it's running on
250 // arm device. Here needs some further check for real system abi.
252 Process process = Runtime.getRuntime().exec("getprop ro.product.cpu.abi");
253 InputStreamReader ir = new InputStreamReader(process.getInputStream());
254 BufferedReader input = new BufferedReader(ir);
255 String abi = input.readLine();
256 sRunningOnIA = abi.contains("x86");
259 } catch (IOException e) {
260 Log.w(TAG, Log.getStackTraceString(e));