Upstream version 10.38.217.0
[platform/framework/web/crosswalk.git] / src / xwalk / runtime / android / core_internal / src / org / xwalk / core / internal / XWalkViewDelegate.java
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.
4
5 package org.xwalk.core.internal;
6
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;
13 import java.util.Set;
14
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;
20
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;
33
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 = {
41             "xwalk.pak",
42             "en-US.pak",
43             "icudtl.dat"
44     };
45     private static final String[] MANDATORY_LIBRARIES = {
46             "libxwalkcore.so"
47     };
48     private static final String TAG = "XWalkViewDelegate";
49     private static final String XWALK_RESOURCES_LIST_RES_NAME = "xwalk_resources_list";
50
51     private static final String COMMAND_LINE_FILE = "xwalk-command-line";
52
53     private static String[] readCommandLine(Context context) {
54         InputStreamReader reader = null;
55
56         try {
57             InputStream input =
58                     context.getAssets().open(COMMAND_LINE_FILE, AssetManager.ACCESS_BUFFER);
59             int length;
60             int size = 1024;
61             char[] buffer = new char[size];
62             StringBuilder builder = new StringBuilder();
63
64             reader = new InputStreamReader(input, "UTF-8");
65             while ((length = reader.read(buffer, 0, size)) != -1) {
66                 builder.append(buffer, 0, length);
67             }
68
69             return CommandLine.tokenizeQuotedAruments(
70                     builder.toString().toCharArray());
71         } catch (IOException e) {
72             return null;
73         } finally {
74             try {
75                 if (reader != null) reader.close();
76             } catch (IOException e) {
77                 Log.e(TAG, "Unable to close file reader.", e);
78             }
79         }
80     }
81
82     public static void loadXWalkLibrary(Context context) throws UnsatisfiedLinkError {
83         if (sLibraryLoaded) return;
84
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);
97             }
98         }
99         loadLibrary(context);
100
101         if (sRunningOnIA && !nativeIsLibraryBuiltForIA()) {
102             throw new UnsatisfiedLinkError();
103         }
104         sLibraryLoaded = true;
105     }
106
107     public static void init(XWalkViewInternal xwalkView) throws UnsatisfiedLinkError {
108         if (sInitialized) {
109             return;
110         }
111
112         loadXWalkLibrary(xwalkView.getContext());
113
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());
117
118         // Auto detect network connectivity state.
119         // setAutoDetectConnectivityState() need to be called before activity started.
120         NetworkChangeNotifier.init(xwalkView.getActivity());
121         NetworkChangeNotifier.setAutoDetectConnectivityState(true);
122
123         // We will miss activity onCreate() status in ApplicationStatusManager,
124         // informActivityStarted() will simulate these callbacks.
125         ApplicationStatusManager.informActivityStarted(xwalkView.getActivity());
126
127         final Context context = xwalkView.getViewContext();
128
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()));
135         }
136
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() {
146
147                 @Override
148                 public Set<String> getInterceptableResourceList() {
149                     Set<String> resourcesList = new HashSet<String>();
150                     if (!context.getPackageName().equals(
151                             context.getApplicationContext().getPackageName())) {
152                         try {
153                             for (String resource : assets.list("")) {
154                                 resourcesList.add(resource);
155                             }
156                         } catch (IOException e){}
157                     }
158                     if (resourcesListResId != 0) {
159                         try {
160                             String[] resources = context.getResources().getStringArray(resourcesListResId);
161                             for (String resource : resources) {
162                                 resourcesList.add(resource);
163                             }
164                         } catch (NotFoundException e) {
165                             Log.w(TAG, "R.array." + XWALK_RESOURCES_LIST_RES_NAME + " can't be found.");
166                         }
167                     }
168                     return resourcesList;
169                 }
170
171                 @Override
172                 public InputStream interceptLoadingForResource(String resource) {
173                     if (!context.getPackageName().equals(
174                             context.getApplicationContext().getPackageName())) {
175                         try {
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.");
180                         }
181                     }
182
183                     if (resourcesListResId != 0) {
184                         String resourceName = resource.split("\\.")[0];
185                         int resId = context.getResources().getIdentifier(
186                                 resourceName, "raw", context.getPackageName());
187                         try {
188                             if (resId != 0) return context.getResources().openRawResource(resId);
189                         } catch (NotFoundException e) {
190                             Log.w(TAG, "R.raw." + resourceName + " can't be found.");
191                         }
192                     }
193
194                     return null;
195                 }
196             });
197         }
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);
202
203         startBrowserProcess(context);
204         sInitialized = true;
205     }
206
207     private static void loadLibrary(Context context) {
208         PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
209         try {
210             LibraryLoader.loadNow(context, true);
211         } catch (ProcessInitException e) {
212             throw new RuntimeException("Cannot load Crosswalk Core", e);
213         }
214     }
215
216     private static void startBrowserProcess(final Context context) {
217         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
218             @Override
219             public void run() {
220                 try {
221                     LibraryLoader.ensureInitialized();
222                 } catch (ProcessInitException e) {
223                     throw new RuntimeException("Cannot initialize Crosswalk Core", e);
224                 }
225                 DeviceUtils.addDeviceSpecificUserAgentSwitch(context);
226                 CommandLine.getInstance().appendSwitchWithValue(
227                         XWalkSwitches.PROFILE_NAME,
228                         XWalkPreferencesInternal.getStringValue(XWalkPreferencesInternal.PROFILE_NAME));
229                 try {
230                     BrowserStartupController.get(context).startBrowserProcessesSync(
231                         true);
232                 } catch (ProcessInitException e) {
233                     throw new RuntimeException("Cannot initialize Crosswalk Core", e);
234                 }
235             }
236         });
237     }
238
239     public static boolean isRunningOnIA() {
240         return sRunningOnIA;
241     }
242
243     private static native boolean nativeIsLibraryBuiltForIA();
244
245     static {
246         sRunningOnIA = Build.CPU_ABI.equalsIgnoreCase("x86");
247         if (!sRunningOnIA) {
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.
251             try {
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");
257                 input.close();
258                 ir.close();
259             } catch (IOException e) {
260                 Log.w(TAG, Log.getStackTraceString(e));
261             }
262         }
263     }
264 }