1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.webkit; 18 19 import android.app.ActivityManager; 20 import android.content.Context; 21 import android.net.Uri; 22 import android.provider.Settings; 23 import android.util.Log; 24 25 import java.io.InputStream; 26 27 class JniUtil { 28 29 static { 30 System.loadLibrary("webcore"); 31 System.loadLibrary("chromium_net"); 32 } 33 private static final String LOGTAG = "webkit"; JniUtil()34 private JniUtil() {} // Utility class, do not instantiate. 35 36 // Used by the Chromium HTTP stack. 37 private static String sDatabaseDirectory; 38 private static String sCacheDirectory; 39 private static Boolean sUseChromiumHttpStack; 40 private static Context sContext; 41 checkInitialized()42 private static void checkInitialized() { 43 if (sContext == null) { 44 throw new IllegalStateException("Call CookieSyncManager::createInstance() or create a webview before using this class"); 45 } 46 } 47 setContext(Context context)48 protected static synchronized void setContext(Context context) { 49 if (sContext != null) { 50 return; 51 } 52 53 sContext = context.getApplicationContext(); 54 } 55 getContext()56 protected static synchronized Context getContext() { 57 return sContext; 58 } 59 60 /** 61 * Called by JNI. Gets the application's database directory, excluding the trailing slash. 62 * @return String The application's database directory 63 */ getDatabaseDirectory()64 private static synchronized String getDatabaseDirectory() { 65 checkInitialized(); 66 67 if (sDatabaseDirectory == null) { 68 sDatabaseDirectory = sContext.getDatabasePath("dummy").getParent(); 69 } 70 71 return sDatabaseDirectory; 72 } 73 74 /** 75 * Called by JNI. Gets the application's cache directory, excluding the trailing slash. 76 * @return String The application's cache directory 77 */ getCacheDirectory()78 private static synchronized String getCacheDirectory() { 79 checkInitialized(); 80 81 if (sCacheDirectory == null) { 82 sCacheDirectory = sContext.getCacheDir().getAbsolutePath(); 83 } 84 85 return sCacheDirectory; 86 } 87 88 private static final String ANDROID_CONTENT = "content:"; 89 90 /** 91 * Called by JNI. Calculates the size of an input stream by reading it. 92 * @return long The size of the stream 93 */ contentUrlSize(String url)94 private static synchronized long contentUrlSize(String url) { 95 // content:// 96 if (url.startsWith(ANDROID_CONTENT)) { 97 try { 98 // Strip off mimetype, for compatibility with ContentLoader.java 99 // If we don't do this, we can fail to load Gmail attachments, 100 // because the URL being loaded doesn't exactly match the URL we 101 // have permission to read. 102 int mimeIndex = url.lastIndexOf('?'); 103 if (mimeIndex != -1) { 104 url = url.substring(0, mimeIndex); 105 } 106 Uri uri = Uri.parse(url); 107 InputStream is = sContext.getContentResolver().openInputStream(uri); 108 byte[] buffer = new byte[1024]; 109 int n; 110 long size = 0; 111 try { 112 while ((n = is.read(buffer)) != -1) { 113 size += n; 114 } 115 } finally { 116 is.close(); 117 } 118 return size; 119 } catch (Exception e) { 120 Log.e(LOGTAG, "Exception: " + url); 121 return 0; 122 } 123 } else { 124 return 0; 125 } 126 } 127 128 /** 129 * Called by JNI. 130 * 131 * @return Opened input stream to content 132 * TODO: Make all content loading use this instead of BrowserFrame.java 133 */ contentUrlStream(String url)134 private static synchronized InputStream contentUrlStream(String url) { 135 // content:// 136 if (url.startsWith(ANDROID_CONTENT)) { 137 try { 138 // Strip off mimetype, for compatibility with ContentLoader.java 139 // If we don't do this, we can fail to load Gmail attachments, 140 // because the URL being loaded doesn't exactly match the URL we 141 // have permission to read. 142 int mimeIndex = url.lastIndexOf('?'); 143 if (mimeIndex != -1) { 144 url = url.substring(0, mimeIndex); 145 } 146 Uri uri = Uri.parse(url); 147 return sContext.getContentResolver().openInputStream(uri); 148 } catch (Exception e) { 149 Log.e(LOGTAG, "Exception: " + url); 150 return null; 151 } 152 } else { 153 return null; 154 } 155 } 156 157 /** 158 * Returns true if we're using the Chromium HTTP stack. 159 * 160 * TODO: Remove this if/when we permanently switch to the Chromium HTTP stack 161 * http:/b/3118772 162 */ useChromiumHttpStack()163 static boolean useChromiumHttpStack() { 164 if (sUseChromiumHttpStack == null) { 165 sUseChromiumHttpStack = nativeUseChromiumHttpStack(); 166 } 167 return sUseChromiumHttpStack; 168 } 169 getAutofillQueryUrl()170 private static synchronized String getAutofillQueryUrl() { 171 checkInitialized(); 172 // If the device has not checked in it won't have pulled down the system setting for the 173 // Autofill Url. In that case we will not make autofill server requests. 174 return Settings.Secure.getString(sContext.getContentResolver(), 175 Settings.Secure.WEB_AUTOFILL_QUERY_URL); 176 } 177 canSatisfyMemoryAllocation(long bytesRequested)178 private static boolean canSatisfyMemoryAllocation(long bytesRequested) { 179 checkInitialized(); 180 ActivityManager manager = (ActivityManager) sContext.getSystemService( 181 Context.ACTIVITY_SERVICE); 182 ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo(); 183 manager.getMemoryInfo(memInfo); 184 long leftToAllocate = memInfo.availMem - memInfo.threshold; 185 return !memInfo.lowMemory && bytesRequested < leftToAllocate; 186 } 187 188 nativeUseChromiumHttpStack()189 private static native boolean nativeUseChromiumHttpStack(); 190 } 191