author | Wes Johnston <wjohnston@mozilla.com> |
Thu, 08 Mar 2012 10:25:44 -0800 | |
changeset 88830 | 2eae96792a75e67abf4e5286f438f2e579bac8cb |
parent 88829 | f34baebe186578280e2bd964b73cc33559069ec5 |
child 88831 | 5031b59e031dc1c4e24851f1453b4d1f4bcd497c |
push id | 22230 |
push user | mak77@bonardo.net |
push date | Tue, 13 Mar 2012 10:17:55 +0000 |
treeherder | mozilla-central@a0fa0eb17298 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | blassey, bsmith |
bugs | 718760 |
milestone | 13.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/embedding/android/GeckoAppShell.java +++ b/embedding/android/GeckoAppShell.java @@ -110,16 +110,17 @@ public class GeckoAppShell public static native void setSurfaceView(GeckoSurfaceView sv); public static native void putenv(String map); public static native void onResume(); public static native void onLowMemory(); public static native void callObserver(String observerKey, String topic, String data); public static native void removeObserver(String observerKey); public static native void loadGeckoLibsNative(String apkName); public static native void loadSQLiteLibsNative(String apkName, boolean shouldExtract); + public static native void loadNSSLibsNative(String apkName, boolean shouldExtract); public static native void onChangeNetworkLinkStatus(String status); public static native void reportJavaCrash(String stack); public static native void processNextNativeEvent(); public static native void notifyBatteryChange(double aLevel, boolean aCharging, double aRemainingTime); public static native void notifySmsReceived(String aSender, String aBody, long aTimestamp); @@ -393,16 +394,17 @@ public class GeckoAppShell while (cacheFiles.hasNext()) { File libFile = (File)cacheFiles.next(); if (libFile.getName().endsWith(".so")) libFile.delete(); } } } loadSQLiteLibsNative(apkName, extractLibs); + loadNSSLibsNative(apkName, extractLibs); loadGeckoLibsNative(apkName); } private static void putLocaleEnv() { GeckoAppShell.putenv("LANG=" + Locale.getDefault().toString()); NumberFormat nf = NumberFormat.getInstance(); if (nf instanceof DecimalFormat) { DecimalFormat df = (DecimalFormat)nf;
--- a/mobile/android/base/AndroidManifest.xml.in +++ b/mobile/android/base/AndroidManifest.xml.in @@ -18,16 +18,17 @@ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION"/> <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/> <uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.VIBRATE"/> + <uses-permission android:name="@ANDROID_PACKAGE_NAME@.permissions.PASSWORD_PROVIDER"/> #ifdef MOZ_WEBSMS_BACKEND <!-- WebSMS --> <uses-permission android:name="android.permission.SEND_SMS"/> <uses-permission android:name="android.permission.RECEIVE_SMS"/> <uses-permission android:name="android.permission.WRITE_SMS"/> <uses-permission android:name="android.permission.READ_SMS"/> #endif @@ -111,16 +112,23 @@ <receiver android:name="NotificationHandler"> <intent-filter> <action android:name="org.mozilla.gecko.ACTION_ALERT_CLICK" /> <action android:name="org.mozilla.gecko.ACTION_ALERT_CLEAR" /> </intent-filter> </receiver> + <receiver android:name="org.mozilla.gecko.GeckoMessageReceiver" + android:permission="@ANDROID_PACKAGE_NAME@.permissions.PASSWORD_PROVIDER"> + <intent-filter> + <action android:name="org.mozilla.gecko.INIT_PW"></action> + </intent-filter> + </receiver> + <activity android:name="Restarter" android:process="@ANDROID_PACKAGE_NAME@Restarter" android:theme="@style/Gecko" android:excludeFromRecents="true"> <intent-filter> <action android:name="org.mozilla.gecko.restart"/> <action android:name="org.mozilla.gecko.restart_update"/> </intent-filter> @@ -170,30 +178,33 @@ android:excludeFromRecents="true"/> <provider android:name="@ANDROID_PACKAGE_NAME@.db.BrowserProvider" android:authorities="@ANDROID_PACKAGE_NAME@.db.browser" android:permission="@ANDROID_PACKAGE_NAME@.permissions.BROWSER_PROVIDER"/> <provider android:name="@ANDROID_PACKAGE_NAME@.db.PasswordsProvider" android:authorities="@ANDROID_PACKAGE_NAME@.db.passwords" - android:permission="@ANDROID_PACKAGE_NAME@.permissions.BROWSER_PROVIDER" - android:protectionLevel="signature"/> + android:permission="@ANDROID_PACKAGE_NAME@.permissions.PASSWORD_PROVIDER" + android:process="org.mozilla.gecko.PasswordsProvider"/> <provider android:name="@ANDROID_PACKAGE_NAME@.db.FormHistoryProvider" android:authorities="@ANDROID_PACKAGE_NAME@.db.formhistory" android:permission="@ANDROID_PACKAGE_NAME@.permissions.FORMHISTORY_PROVIDER" android:protectionLevel="signature"/> <provider android:name="@ANDROID_PACKAGE_NAME@.db.TabsProvider" android:authorities="@ANDROID_PACKAGE_NAME@.db.tabs" android:permission="@ANDROID_PACKAGE_NAME@.permissions.BROWSER_PROVIDER"/> #include ../sync/manifests/SyncAndroidManifest_services.xml.in </application> <permission android:name="@ANDROID_PACKAGE_NAME@.permissions.BROWSER_PROVIDER" android:protectionLevel="signature"/> + <permission android:name="@ANDROID_PACKAGE_NAME@.permissions.PASSWORD_PROVIDER" + android:protectionLevel="signature"/> + <permission android:name="@ANDROID_PACKAGE_NAME@.permissions.FORMHISTORY_PROVIDER" android:protectionLevel="signature"/> </manifest>
--- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -104,16 +104,17 @@ abstract public class GeckoApp public static final String ACTION_ALERT_CLICK = "org.mozilla.gecko.ACTION_ALERT_CLICK"; public static final String ACTION_ALERT_CLEAR = "org.mozilla.gecko.ACTION_ALERT_CLEAR"; public static final String ACTION_WEBAPP = "org.mozilla.gecko.WEBAPP"; public static final String ACTION_DEBUG = "org.mozilla.gecko.DEBUG"; public static final String ACTION_BOOKMARK = "org.mozilla.gecko.BOOKMARK"; public static final String ACTION_LOAD = "org.mozilla.gecko.LOAD"; public static final String ACTION_UPDATE = "org.mozilla.gecko.UPDATE"; + public static final String ACTION_INIT_PW = "org.mozilla.gecko.INIT_PW"; public static final String SAVED_STATE_URI = "uri"; public static final String SAVED_STATE_TITLE = "title"; public static final String SAVED_STATE_VIEWPORT = "viewport"; public static final String SAVED_STATE_SCREEN = "screen"; public static final String SAVED_STATE_SESSION = "session"; StartupMode mStartupMode = null; private LinearLayout mMainLayout;
--- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -107,16 +107,17 @@ public class GeckoAppShell static public final int WPL_STATE_IS_DOCUMENT = 0x00020000; static public final int WPL_STATE_IS_NETWORK = 0x00040000; static private File sCacheFile = null; static private int sFreeSpace = -1; static File sHomeDir = null; static private int sDensityDpi = 0; private static Boolean sSQLiteLibsLoaded = false; + private static Boolean sNSSLibsLoaded = false; private static Boolean sLibsSetup = false; private static File sGREDir = null; private static HashMap<String, ArrayList<GeckoEventListener>> mEventListeners; /* Is the value in sVibrationEndTime valid? */ private static boolean sVibrationMaybePlaying = false; @@ -136,16 +137,17 @@ public class GeckoAppShell public static native void setSoftwareLayerClient(GeckoSoftwareLayerClient client); public static native void putenv(String map); public static native void onResume(); public static native void onLowMemory(); public static native void callObserver(String observerKey, String topic, String data); public static native void removeObserver(String observerKey); public static native void loadGeckoLibsNative(String apkName); public static native void loadSQLiteLibsNative(String apkName, boolean shouldExtract); + public static native void loadNSSLibsNative(String apkName, boolean shouldExtract); public static native void onChangeNetworkLinkStatus(String status); public static void registerGlobalExceptionHandler() { Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { public void uncaughtException(Thread thread, Throwable e) { Log.e(LOGTAG, ">>> REPORTING UNCAUGHT EXCEPTION FROM THREAD " + thread.getId() + " (\"" + thread.getName() + "\")", e); reportJavaCrash(getStackTraceString(e)); @@ -366,16 +368,29 @@ public class GeckoAppShell loadMozGlue(); // the extract libs parameter is being removed in bug 732069 loadLibsSetup(context); loadSQLiteLibsNative(apkName, false); sSQLiteLibsLoaded = true; } } + public static void loadNSSLibs(Context context, String apkName) { + if (sNSSLibsLoaded) + return; + synchronized(sNSSLibsLoaded) { + if (sNSSLibsLoaded) + return; + loadMozGlue(); + loadLibsSetup(context); + loadNSSLibsNative(apkName, false); + sNSSLibsLoaded = true; + } + } + public static void loadMozGlue() { System.loadLibrary("mozglue"); } public static void loadGeckoLibs(String apkName) { loadLibsSetup(GeckoApp.mAppContext); loadGeckoLibsNative(apkName); }
new file mode 100644 --- /dev/null +++ b/mobile/android/base/GeckoMessageReceiver.java @@ -0,0 +1,20 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +public class GeckoMessageReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (GeckoApp.ACTION_INIT_PW.equals(action)) { + GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Passwords:Init", null)); + } + } +}
--- a/mobile/android/base/GeckoThread.java +++ b/mobile/android/base/GeckoThread.java @@ -85,16 +85,17 @@ public class GeckoThread extends Thread // At some point while loading the gecko libs our default locale gets set // so just save it to locale here and reset it as default after the join Locale locale = Locale.getDefault(); String resourcePath = app.getApplication().getPackageResourcePath(); GeckoAppShell.setupGeckoEnvironment(app); GeckoAppShell.loadSQLiteLibs(app, resourcePath); + GeckoAppShell.loadNSSLibs(app, resourcePath); GeckoAppShell.loadGeckoLibs(resourcePath); Locale.setDefault(locale); Resources res = app.getBaseContext().getResources(); Configuration config = res.getConfiguration(); config.locale = locale; res.updateConfiguration(config, res.getDisplayMetrics());
--- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -83,23 +83,25 @@ FENNEC_JAVA_FILES = \ GeckoAsyncTask.java \ GeckoBatteryManager.java \ GeckoBackgroundThread.java \ GeckoConnectivityReceiver.java \ GeckoEvent.java \ GeckoEventListener.java \ GeckoEventResponder.java \ GeckoInputConnection.java \ + GeckoMessageReceiver.java \ GeckoPreferences.java \ GeckoProfile.java \ GeckoStateListDrawable.java \ GeckoThread.java \ GlobalHistory.java \ LinkPreference.java \ LinkTextView.java \ + NSSBridge.java \ ProfileMigrator.java \ PromptService.java \ sqlite/ByteBufferInputStream.java \ sqlite/MatrixBlobCursor.java \ sqlite/SQLiteBridge.java \ sqlite/SQLiteBridgeException.java \ RemoteTabs.java \ SetupScreen.java \
new file mode 100644 --- /dev/null +++ b/mobile/android/base/NSSBridge.java @@ -0,0 +1,63 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import android.app.Activity; +import android.util.Log; +import android.content.Context; +import java.lang.String; + +public class NSSBridge { + private static final String LOGTAG = "NSSBridge"; + + private static native String nativeEncrypt(String aDb, String aValue); + private static native String nativeDecrypt(String aDb, String aValue); + + static public String encrypt(Context context, String aValue) { + String resourcePath = context.getPackageResourcePath(); + GeckoAppShell.loadNSSLibs(context, resourcePath); + + String res = ""; + try { + String path = GeckoProfile.get(context).getDir().toString(); + res = nativeEncrypt(path, aValue); + } catch(Exception ex) { } + return res; + } + + static public String encrypt(Context context, String profilePath, String aValue) { + String resourcePath = context.getPackageResourcePath(); + GeckoAppShell.loadNSSLibs(context, resourcePath); + + String res = ""; + try { + res = nativeEncrypt(profilePath, aValue); + } catch(Exception ex) { } + return res; + } + + static public String decrypt(Context context, String aValue) { + String resourcePath = context.getPackageResourcePath(); + GeckoAppShell.loadNSSLibs(context, resourcePath); + + String res = ""; + try { + String path = GeckoProfile.get(context).getDir().toString(); + res = nativeDecrypt(path, aValue); + } catch(Exception ex) { } + return res; + } + + static public String decrypt(Context context, String profilePath, String aValue) { + String resourcePath = context.getPackageResourcePath(); + GeckoAppShell.loadNSSLibs(context, resourcePath); + + String res = ""; + try { + res = nativeDecrypt(profilePath, aValue); + } catch(Exception ex) { } + return res; + } +}
--- a/mobile/android/base/db/BrowserContract.java.in +++ b/mobile/android/base/db/BrowserContract.java.in @@ -40,25 +40,20 @@ package org.mozilla.gecko.db; import android.net.Uri; public class BrowserContract { public static final String AUTHORITY = "@ANDROID_PACKAGE_NAME@.db.browser"; public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY); public static final String PASSWORDS_AUTHORITY = "@ANDROID_PACKAGE_NAME@.db.passwords"; - public static final String DELETED_PASSWORDS_AUTHORITY = "@ANDROID_PACKAGE_NAME@.db.deleted-passwords"; - public static final Uri PASSWORDS_AUTHORITY_URI = Uri.parse("content://" + PASSWORDS_AUTHORITY); - public static final Uri DELETED_PASSWORDS_AUTHORITY_URI = Uri.parse("content://" + DELETED_PASSWORDS_AUTHORITY); public static final String FORM_HISTORY_AUTHORITY = "@ANDROID_PACKAGE_NAME@.db.formhistory"; - public static final String DELETED_FORM_HISTORY_AUTHORITY = "@ANDROID_PACKAGE_NAME@.db.deleted-formhistory"; public static final Uri FORM_HISTORY_AUTHORITY_URI = Uri.parse("content://" + FORM_HISTORY_AUTHORITY); - public static final Uri DELETED_FORM_HISTORY_AUTHORITY_URI = Uri.parse("content://" + DELETED_FORM_HISTORY_AUTHORITY); public static final String TABS_AUTHORITY = "@ANDROID_PACKAGE_NAME@.db.tabs"; public static final Uri TABS_AUTHORITY_URI = Uri.parse("content://" + TABS_AUTHORITY); public static final String DEFAULT_PROFILE = "default"; public static final String PARAM_PROFILE = "profile"; public static final String PARAM_PROFILE_PATH = "profilePath"; public static final String PARAM_LIMIT = "limit"; @@ -163,17 +158,17 @@ public class BrowserContract { public static final String TIME_PASSWORD_CHANGED = "timePasswordChanged"; public static final String TIMES_USED = "timesUsed"; public static final String GUID = "guid"; } public static final class DeletedPasswords implements DeletedColumns { private DeletedPasswords() {} public static final String CONTENT_TYPE = "vnd.android.cursor.dir/deleted-passwords"; - public static final Uri CONTENT_URI = Uri.withAppendedPath(DELETED_PASSWORDS_AUTHORITY_URI, "deleted-formhistory"); + public static final Uri CONTENT_URI = Uri.withAppendedPath(PASSWORDS_AUTHORITY_URI, "deleted-passwords"); } public static final class FormHistory { private FormHistory() {} public static final Uri CONTENT_URI = Uri.withAppendedPath(FORM_HISTORY_AUTHORITY_URI, "formhistory"); public static final String CONTENT_TYPE = "vnd.android.cursor.dir/formhistory"; public static final String ID = "id"; @@ -182,17 +177,17 @@ public class BrowserContract { public static final String TIMES_USED = "timesUsed"; public static final String FIRST_USED = "firstUsed"; public static final String LAST_USED = "lastUsed"; public static final String GUID = "guid"; } public static final class DeletedFormHistory implements DeletedColumns { private DeletedFormHistory() {} - public static final Uri CONTENT_URI = Uri.withAppendedPath(DELETED_FORM_HISTORY_AUTHORITY_URI, "deleted-formhistory"); + public static final Uri CONTENT_URI = Uri.withAppendedPath(FORM_HISTORY_AUTHORITY_URI, "deleted-formhistory"); public static final String CONTENT_TYPE = "vnd.android.cursor.dir/deleted-formhistory"; } public static final class Tabs implements CommonColumns { private Tabs() {} public static final Uri CONTENT_URI = Uri.withAppendedPath(TABS_AUTHORITY_URI, "tabs"); public static final String CONTENT_TYPE = "vnd.android.cursor.dir/tab"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/tab";
--- a/mobile/android/base/db/DBUtils.java +++ b/mobile/android/base/db/DBUtils.java @@ -54,13 +54,13 @@ public class DBUtils { public static void replaceKey(ContentValues aValues, String aOriginalKey, String aNewKey, String aDefault) { String value = aDefault; if (aOriginalKey != null && aValues.containsKey(aOriginalKey)) { value = aValues.get(aOriginalKey).toString(); aValues.remove(aOriginalKey); } - if (!aValues.containsKey(aOriginalKey)) { + if (!aValues.containsKey(aNewKey)) { aValues.put(aNewKey, value); } } }
--- a/mobile/android/base/db/FormHistoryProvider.java.in +++ b/mobile/android/base/db/FormHistoryProvider.java.in @@ -28,19 +28,16 @@ import org.mozilla.gecko.sqlite.SQLiteBr import org.mozilla.gecko.sync.Utils; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.os.Build; import android.text.TextUtils; import android.util.Log; public class FormHistoryProvider extends GeckoProvider { static final String TABLE_FORM_HISTORY = "moz_formhistory"; static final String TABLE_DELETED_FORM_HISTORY = "moz_deleted_formhistory"; @@ -55,17 +52,17 @@ public class FormHistoryProvider extends // This should be kept in sync with the db version in toolkit/components/satchel/nsFormHistory.js private static int DB_VERSION = 4; private static String DB_FILENAME = "formhistory.sqlite"; static { URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); URI_MATCHER.addURI(BrowserContract.FORM_HISTORY_AUTHORITY, "formhistory", FORM_HISTORY); - URI_MATCHER.addURI(BrowserContract.DELETED_FORM_HISTORY_AUTHORITY, "deleted-formhistory", DELETED_FORM_HISTORY); + URI_MATCHER.addURI(BrowserContract.FORM_HISTORY_AUTHORITY, "deleted-formhistory", DELETED_FORM_HISTORY); FORM_HISTORY_PROJECTION_MAP = new HashMap<String, String>(); DELETED_FORM_HISTORY_PROJECTION_MAP = new HashMap<String, String>(); } @Override public boolean onCreate() { setLogTag("FormHistoryProvider"); setDBName(DB_FILENAME); @@ -141,9 +138,15 @@ public class FormHistoryProvider extends default: throw new UnsupportedOperationException("Unknown insert URI " + uri); } } public void initGecko() { GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FormHistory:Init", null)); } + + public void onPreInsert(ContentValues values, Uri uri) { } + + public void onPreUpdate(ContentValues values, Uri uri) { } + + public void onPostQuery(Cursor cursor, Uri uri) { } }
--- a/mobile/android/base/db/GeckoProvider.java.in +++ b/mobile/android/base/db/GeckoProvider.java.in @@ -85,16 +85,17 @@ public abstract class GeckoProvider exte private SQLiteBridge getDB(Context context, final String databasePath) { SQLiteBridge bridge = null; boolean dbNeedsSetup = true; try { String resourcePath = context.getPackageResourcePath(); GeckoAppShell.loadSQLiteLibs(context, resourcePath); + GeckoAppShell.loadNSSLibs(context, resourcePath); bridge = new SQLiteBridge(databasePath); int version = bridge.getVersion(); Log.i(mLogTag, version + " == " + mDBVersion); dbNeedsSetup = version != mDBVersion; } catch(SQLiteBridgeException ex) { // this will throw if the database can't be found // we should attempt to set it up if Gecko is running dbNeedsSetup = true; @@ -216,16 +217,18 @@ public abstract class GeckoProvider exte // If we can not get a SQLiteBridge instance, its likely that the database // has not been set up and Gecko is not running. We return null and expect // callers to try again later if (db == null) return null; setupDefaults(uri, values); + onPreInsert(values, uri); + try { id = db.insert(getTable(uri), null, values); } catch(SQLiteBridgeException ex) { Log.e(mLogTag, "Error inserting in db", ex); } return ContentUris.withAppendedId(uri, id); } @@ -237,16 +240,18 @@ public abstract class GeckoProvider exte final SQLiteBridge db = getDatabase(uri); // If we can not get a SQLiteBridge instance, its likely that the database // has not been set up and Gecko is not running. We return null and expect // callers to try again later if (db == null) return updated; + onPreUpdate(values, uri); + try { updated = db.update(getTable(uri), values, selection, selectionArgs); } catch(SQLiteBridgeException ex) { Log.e(mLogTag, "Error updating table", ex); } return updated; } @@ -262,23 +267,30 @@ public abstract class GeckoProvider exte // callers to try again later if (db == null) return cursor; sortOrder = getSortOrder(uri, sortOrder); try { cursor = db.query(getTable(uri), projection, selection, selectionArgs, null, null, sortOrder, null); + onPostQuery(cursor, uri); } catch (SQLiteBridgeException ex) { Log.e(mLogTag, "Error querying database", ex); } return cursor; } public abstract String getTable(Uri uri); public abstract String getSortOrder(Uri uri, String aRequested); public abstract void setupDefaults(Uri uri, ContentValues values); public abstract void initGecko(); + + public abstract void onPreInsert(ContentValues values, Uri uri); + + public abstract void onPreUpdate(ContentValues values, Uri uri); + + public abstract void onPostQuery(Cursor cursor, Uri uri); }
--- a/mobile/android/base/db/PasswordsProvider.java.in +++ b/mobile/android/base/db/PasswordsProvider.java.in @@ -12,35 +12,34 @@ import java.util.HashMap; import java.util.ArrayList; import java.util.Random; import org.mozilla.gecko.GeckoApp; import org.mozilla.gecko.GeckoAppShell; import org.mozilla.gecko.GeckoEvent; import org.mozilla.gecko.GeckoEventListener; import org.mozilla.gecko.GeckoProfile; -import org.mozilla.gecko.db.BrowserContract.CommonColumns; +import org.mozilla.gecko.NSSBridge; import org.mozilla.gecko.db.DBUtils; import org.mozilla.gecko.db.BrowserContract.Passwords; import org.mozilla.gecko.db.BrowserContract.DeletedPasswords; import org.mozilla.gecko.db.BrowserContract.SyncColumns; import org.mozilla.gecko.db.BrowserContract; +import org.mozilla.gecko.sqlite.MatrixBlobCursor; import org.mozilla.gecko.sqlite.SQLiteBridge; import org.mozilla.gecko.sqlite.SQLiteBridgeException; import org.mozilla.gecko.sync.Utils; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; +import android.content.Intent; import android.content.UriMatcher; import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.os.Build; import android.text.TextUtils; import android.util.Log; public class PasswordsProvider extends GeckoProvider { static final String TABLE_PASSWORDS = "moz_logins"; static final String TABLE_DELETED_PASSWORDS = "moz_deleted_logins"; @@ -77,22 +76,23 @@ public class PasswordsProvider extends G PASSWORDS_PROJECTION_MAP.put(Passwords.ENCRYPTED_PASSWORD, Passwords.ENCRYPTED_PASSWORD); PASSWORDS_PROJECTION_MAP.put(Passwords.GUID, Passwords.GUID); PASSWORDS_PROJECTION_MAP.put(Passwords.ENC_TYPE, Passwords.ENC_TYPE); PASSWORDS_PROJECTION_MAP.put(Passwords.TIME_CREATED, Passwords.TIME_CREATED); PASSWORDS_PROJECTION_MAP.put(Passwords.TIME_LAST_USED, Passwords.TIME_LAST_USED); PASSWORDS_PROJECTION_MAP.put(Passwords.TIME_PASSWORD_CHANGED, Passwords.TIME_PASSWORD_CHANGED); PASSWORDS_PROJECTION_MAP.put(Passwords.TIMES_USED, Passwords.TIMES_USED); - URI_MATCHER.addURI(BrowserContract.DELETED_PASSWORDS_AUTHORITY, "deleted-passwords", DELETED_PASSWORDS); + URI_MATCHER.addURI(BrowserContract.PASSWORDS_AUTHORITY, "deleted-passwords", DELETED_PASSWORDS); DELETED_PASSWORDS_PROJECTION_MAP = new HashMap<String, String>(); DELETED_PASSWORDS_PROJECTION_MAP.put(DeletedPasswords.ID, DeletedPasswords.ID); DELETED_PASSWORDS_PROJECTION_MAP.put(DeletedPasswords.GUID, DeletedPasswords.GUID); DELETED_PASSWORDS_PROJECTION_MAP.put(DeletedPasswords.TIME_DELETED, DeletedPasswords.TIME_DELETED); + System.loadLibrary("mozglue"); } @Override public boolean onCreate() { setLogTag("GeckoPasswordsProvider"); setDBName(DB_FILENAME); setDBVersion(DB_VERSION); return super.onCreate(); @@ -184,10 +184,83 @@ public class PasswordsProvider extends G default: throw new UnsupportedOperationException("Unknown URI " + uri); } } @Override public void initGecko() { GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Passwords:Init", null)); + Intent initIntent = new Intent(GeckoApp.ACTION_INIT_PW); + mContext.sendBroadcast(initIntent); + } + + private String doCrypto(String initialValue, Uri uri, Boolean encrypt) { + String profilePath = null; + if (uri != null) { + profilePath = uri.getQueryParameter(BrowserContract.PARAM_PROFILE_PATH); + } + + String result = ""; + if (encrypt) { + if (profilePath != null) result = NSSBridge.encrypt(mContext, profilePath, initialValue); + else result = NSSBridge.encrypt(mContext, initialValue); + } else { + if (profilePath != null) result = NSSBridge.decrypt(mContext, profilePath, initialValue); + else result = NSSBridge.decrypt(mContext, initialValue); + } + return result; + } + + public void onPreInsert(ContentValues values, Uri uri) { + if (values.containsKey(Passwords.ENCRYPTED_PASSWORD)) { + String res = doCrypto(values.getAsString(Passwords.ENCRYPTED_PASSWORD), uri, true); + values.put(Passwords.ENCRYPTED_PASSWORD, res); + } + + if (values.containsKey(Passwords.ENCRYPTED_USERNAME)) { + String res = doCrypto(values.getAsString(Passwords.ENCRYPTED_USERNAME), uri, true); + values.put(Passwords.ENCRYPTED_USERNAME, res); + } + } + + public void onPreUpdate(ContentValues values, Uri uri) { + if (values.containsKey(Passwords.ENCRYPTED_PASSWORD)) { + String res = doCrypto(values.getAsString(Passwords.ENCRYPTED_PASSWORD), uri, true); + values.put(Passwords.ENCRYPTED_PASSWORD, res); + } + + if (values.containsKey(Passwords.ENCRYPTED_USERNAME)) { + String res = doCrypto(values.getAsString(Passwords.ENCRYPTED_USERNAME), uri, true); + values.put(Passwords.ENCRYPTED_USERNAME, res); + } + } + + public void onPostQuery(Cursor cursor, Uri uri) { + int passwordIndex = -1; + int usernameIndex = -1; + String profilePath = null; + + try { + passwordIndex = cursor.getColumnIndexOrThrow(Passwords.ENCRYPTED_PASSWORD); + } catch(Exception ex) { } + try { + usernameIndex = cursor.getColumnIndexOrThrow(Passwords.ENCRYPTED_USERNAME); + } catch(Exception ex) { } + + if (passwordIndex > -1 || usernameIndex > -1) { + MatrixBlobCursor m = (MatrixBlobCursor)cursor; + if (cursor.moveToFirst()) { + do { + if (passwordIndex > -1) { + String decrypted = doCrypto(cursor.getString(passwordIndex), uri, false);; + m.set(passwordIndex, decrypted); + } + + if (usernameIndex > -1) { + String decrypted = doCrypto(cursor.getString(usernameIndex), uri, false); + m.set(usernameIndex, decrypted); + } + } while(cursor.moveToNext()); + } + } } }
--- a/mobile/android/base/sqlite/MatrixBlobCursor.java +++ b/mobile/android/base/sqlite/MatrixBlobCursor.java @@ -223,18 +223,31 @@ public class MatrixBlobCursor extends Ab "No more columns left."); } data[index++] = columnValue; return this; } } + public void set(int column, Object value) { + if (column < 0 || column >= columnCount) { + throw new CursorIndexOutOfBoundsException("Requested column: " + + column + ", # of columns: " + columnCount); + } + if (mPos < 0) { + throw new CursorIndexOutOfBoundsException("Before first row."); + } + if (mPos >= rowCount) { + throw new CursorIndexOutOfBoundsException("After last row."); + } + data[mPos * columnCount + column] = value; + } + // AbstractCursor implementation. - @Override public int getCount() { return rowCount; } @Override public String[] getColumnNames() { return columnNames;
--- a/mozglue/android/APKOpen.cpp +++ b/mozglue/android/APKOpen.cpp @@ -61,26 +61,29 @@ #endif #include "dlfcn.h" #include "APKOpen.h" #include <sys/time.h> #include <sys/resource.h> #include "Zip.h" #include "sqlite3.h" #include "SQLiteBridge.h" +#include "NSSBridge.h" #ifndef MOZ_OLD_LINKER #include "ElfLoader.h" #endif #include "application.ini.h" /* Android headers don't define RUSAGE_THREAD */ #ifndef RUSAGE_THREAD #define RUSAGE_THREAD 1 #endif +typedef int mozglueresult; + enum StartupEvent { #define mozilla_StartupTimeline_Event(ev, z) ev, #include "StartupTimeline.h" #undef mozilla_StartupTimeline_Event }; using namespace mozilla; @@ -94,16 +97,33 @@ void StartupTimeline_Record(StartupEvent static struct mapping_info * lib_mapping = NULL; NS_EXPORT const struct mapping_info * getLibraryMapping() { return lib_mapping; } +void +JNI_Throw(JNIEnv* jenv, const char* classname, const char* msg) +{ + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Throw\n"); + jclass cls = jenv->FindClass(classname); + if (cls == NULL) { + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't find exception class (or exception pending) %s\n", classname); + exit(FAILURE); + } + int rc = jenv->ThrowNew(cls, msg); + if (rc < 0) { + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Error throwing exception %s\n", msg); + exit(FAILURE); + } + jenv->DeleteLocalRef(cls); +} + #ifdef MOZ_OLD_LINKER static int createAshmem(size_t bytes, const char *name) { int fd = open("/" ASHMEM_NAME_DEF, O_RDWR, 0600); if (fd < 0) return -1; @@ -308,16 +328,21 @@ SHELL_WRAPPER3(notifySmsDeleted, jboolea SHELL_WRAPPER3(notifySmsDeleteFailed, jint, jint, jlong) SHELL_WRAPPER2(notifyNoMessageInList, jint, jlong) SHELL_WRAPPER8(notifyListCreated, jint, jint, jstring, jstring, jstring, jlong, jint, jlong) SHELL_WRAPPER7(notifyGotNextMessage, jint, jstring, jstring, jstring, jlong, jint, jlong) SHELL_WRAPPER3(notifyReadingMessageListFailed, jint, jint, jlong) static void * xul_handle = NULL; static void * sqlite_handle = NULL; +static void * nss_handle = NULL; +static void * nspr_handle = NULL; +static void * plc_handle = NULL; +static bool simple_linker_initialized = false; + #ifdef MOZ_OLD_LINKER static time_t apk_mtime = 0; #ifdef DEBUG extern "C" int extractLibs = 1; #else extern "C" int extractLibs = 0; #endif @@ -636,17 +661,17 @@ report_mapping(char *name, void *base, u if (entry) info->file_id = strndup(entry + strlen(name) + 1, 32); } #ifdef MOZ_OLD_LINKER extern "C" void simple_linker_init(void); #endif -static void +static mozglueresult loadGeckoLibs(const char *apkName) { chdir(getenv("GRE_HOME")); #ifdef MOZ_OLD_LINKER struct stat status; if (!stat(apkName, &status)) apk_mtime = status.st_mtime; @@ -668,38 +693,30 @@ loadGeckoLibs(const char *apkName) sprintf(file, "%s!/libxpcom.so", apkName); __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY); // libxul.so is pulled from libxpcom.so, so we don't need to give the full path xul_handle = __wrap_dlopen("libxul.so", RTLD_GLOBAL | RTLD_LAZY); delete[] file; #else #define MOZLOAD(name) mozload("lib" name ".so", zip) MOZLOAD("mozalloc"); - MOZLOAD("nspr4"); - MOZLOAD("plc4"); - MOZLOAD("plds4"); - MOZLOAD("nssutil3"); - MOZLOAD("nss3"); - MOZLOAD("ssl3"); - MOZLOAD("smime3"); xul_handle = MOZLOAD("xul"); MOZLOAD("xpcom"); - MOZLOAD("nssckbi"); - MOZLOAD("freebl3"); - MOZLOAD("softokn3"); #undef MOZLOAD #endif #ifdef MOZ_CRASHREPORTER free(file_ids); file_ids = NULL; #endif - if (!xul_handle) + if (!xul_handle) { __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libxul!"); + return FAILURE; + } #define GETFUNC(name) f_ ## name = (name ## _t) __wrap_dlsym(xul_handle, "Java_org_mozilla_gecko_GeckoAppShell_" #name) GETFUNC(nativeInit); GETFUNC(notifyGeckoOfEvent); GETFUNC(processNextNativeEvent); GETFUNC(setSurfaceView); GETFUNC(setSoftwareLayerClient); GETFUNC(onResume); @@ -733,32 +750,38 @@ loadGeckoLibs(const char *apkName) __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Loaded libs in %ldms total, %ldms user, %ldms system, %ld faults", (t1.tv_sec - t0.tv_sec)*1000 + (t1.tv_usec - t0.tv_usec)/1000, (usage2.ru_utime.tv_sec - usage1.ru_utime.tv_sec)*1000 + (usage2.ru_utime.tv_usec - usage1.ru_utime.tv_usec)/1000, (usage2.ru_stime.tv_sec - usage1.ru_stime.tv_sec)*1000 + (usage2.ru_stime.tv_usec - usage1.ru_stime.tv_usec)/1000, usage2.ru_majflt-usage1.ru_majflt); StartupTimeline_Record(LINKER_INITIALIZED, &t0); StartupTimeline_Record(LIBRARIES_LOADED, &t1); + return SUCCESS; } -static void loadSQLiteLibs(const char *apkName) +static int loadSQLiteLibs(const char *apkName) { chdir(getenv("GRE_HOME")); #ifdef MOZ_OLD_LINKER - simple_linker_init(); + if (!simple_linker_initialized) { + simple_linker_init(); + simple_linker_initialized = true; + } struct stat status; if (!stat(apkName, &status)) apk_mtime = status.st_mtime; #endif RefPtr<Zip> zip = new Zip(apkName); - lib_mapping = (struct mapping_info *)calloc(MAX_MAPPING_INFO, sizeof(*lib_mapping)); + if (!lib_mapping) { + lib_mapping = (struct mapping_info *)calloc(MAX_MAPPING_INFO, sizeof(*lib_mapping)); + } #ifdef MOZ_CRASHREPORTER file_ids = (char *)extractBuf("lib.id", zip); #endif #ifndef MOZ_OLD_LINKER char *file = new char[strlen(apkName) + sizeof("!/libmozsqlite3.so")]; sprintf(file, "%s!/libmozsqlite3.so", apkName); @@ -770,33 +793,122 @@ static void loadSQLiteLibs(const char *a #undef MOZLOAD #endif #ifdef MOZ_CRASHREPORTER free(file_ids); file_ids = NULL; #endif - if (!sqlite_handle) + if (!sqlite_handle) { __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libmozsqlite3!"); + return FAILURE; + } setup_sqlite_functions(sqlite_handle); + return SUCCESS; +} + +static mozglueresult +loadNSSLibs(const char *apkName) +{ + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "loadNSSLibs"); + chdir(getenv("GRE_HOME")); + +#ifdef MOZ_OLD_LINKER + if (!simple_linker_initialized) { + simple_linker_init(); + simple_linker_initialized = true; + } + + struct stat status; + if (!stat(apkName, &status)) + apk_mtime = status.st_mtime; +#endif + + Zip *zip = new Zip(apkName); + if (!lib_mapping) { + lib_mapping = (struct mapping_info *)calloc(MAX_MAPPING_INFO, sizeof(*lib_mapping)); + } + +#ifdef MOZ_CRASHREPORTER + file_ids = (char *)extractBuf("lib.id", zip); +#endif + +#ifndef MOZ_OLD_LINKER + char *file = new char[strlen(apkName) + sizeof("!/libnss3.so")]; + sprintf(file, "%s!/libnss3.so", apkName); + nss_handle = __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY); + delete [] file; + + file = new char[strlen(apkName) + sizeof("!/libnspr4.so")]; + sprintf(file, "%s!/libnspr4.so", apkName); + nspr_handle = __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY); + delete [] file; + + file = new char[strlen(apkName) + sizeof("!/libplc4.so")]; + sprintf(file, "%s!/libplc4.so", apkName); + plc_handle = __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY); + delete [] file; +#else +#define MOZLOAD(name) mozload("lib" name ".so", zip) + nspr_handle = MOZLOAD("nspr4"); + plc_handle = MOZLOAD("plc4"); + MOZLOAD("plds4"); + MOZLOAD("nssutil3"); + nss_handle = MOZLOAD("nss3"); + MOZLOAD("ssl3"); + MOZLOAD("smime3"); + MOZLOAD("nssckbi"); + MOZLOAD("freebl3"); + MOZLOAD("softokn3"); +#undef MOZLOAD +#endif + + delete zip; + +#ifdef MOZ_CRASHREPORTER + free(file_ids); + file_ids = NULL; +#endif + + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "loadNSSLibs 2"); + if (!nss_handle) { + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libnss3!"); + return FAILURE; + } + + if (!nspr_handle) { + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libnspr4!"); + return FAILURE; + } + + if (!plc_handle) { + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libplc4!"); + return FAILURE; + } + + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "loadNSSLibs 3"); + return setup_nss_functions(nss_handle, nspr_handle, plc_handle); } extern "C" NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_loadGeckoLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName) { const char* str; // XXX: java doesn't give us true UTF8, we should figure out something // better to do here str = jenv->GetStringUTFChars(jApkName, NULL); if (str == NULL) return; - loadGeckoLibs(str); + int res = loadGeckoLibs(str); + if (res != SUCCESS) { + JNI_Throw(jenv, "java/lang/Exception", "Error loading gecko libraries"); + } jenv->ReleaseStringUTFChars(jApkName, str); } extern "C" NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_loadSQLiteLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName, jboolean jShouldExtract) { if (jShouldExtract) { #ifdef MOZ_OLD_LINKER extractLibs = 1; @@ -807,17 +919,48 @@ Java_org_mozilla_gecko_GeckoAppShell_loa const char* str; // XXX: java doesn't give us true UTF8, we should figure out something // better to do here str = jenv->GetStringUTFChars(jApkName, NULL); if (str == NULL) return; - loadSQLiteLibs(str); + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load sqlite start\n"); + mozglueresult rv = loadSQLiteLibs(str); + if (rv != SUCCESS) { + JNI_Throw(jenv, "java/lang/Exception", "Error loading sqlite libraries"); + } + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load sqlite done\n"); + jenv->ReleaseStringUTFChars(jApkName, str); +} + +extern "C" NS_EXPORT void JNICALL +Java_org_mozilla_gecko_GeckoAppShell_loadNSSLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName, jboolean jShouldExtract) { + if (jShouldExtract) { +#ifdef MOZ_OLD_LINKER + extractLibs = 1; +#else + putenv("MOZ_LINKER_EXTRACT=1"); +#endif + } + + const char* str; + // XXX: java doesn't give us true UTF8, we should figure out something + // better to do here + str = jenv->GetStringUTFChars(jApkName, NULL); + if (str == NULL) + return; + + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load nss start\n"); + mozglueresult rv = loadNSSLibs(str); + if (rv != SUCCESS) { + JNI_Throw(jenv, "java/lang/Exception", "Error loading nss libraries"); + } + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load nss done\n"); jenv->ReleaseStringUTFChars(jApkName, str); } typedef void (*GeckoStart_t)(void *, const nsXREAppData *); extern "C" NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_nativeRun(JNIEnv *jenv, jclass jc, jstring jargs) { @@ -831,47 +974,49 @@ Java_org_mozilla_gecko_GeckoAppShell_nat char *args = (char *) malloc(len + 1); jenv->GetStringUTFRegion(jargs, 0, len, args); args[len] = '\0'; GeckoStart(args, &sAppData); free(args); } typedef int GeckoProcessType; -typedef int nsresult; -extern "C" NS_EXPORT int +extern "C" NS_EXPORT mozglueresult ChildProcessInit(int argc, char* argv[]) { int i; for (i = 0; i < (argc - 1); i++) { if (strcmp(argv[i], "-greomni")) continue; i = i + 1; break; } #ifdef MOZ_OLD_LINKER fillLibCache(argv[argc - 1]); #endif - loadSQLiteLibs(argv[i]); - loadGeckoLibs(argv[i]); + if (loadNSSLibs(argv[i]) != SUCCESS) { + return FAILURE; + } + if (loadSQLiteLibs(argv[i]) != SUCCESS) { + return FAILURE; + } + if (loadGeckoLibs(argv[i]) != SUCCESS) { + return FAILURE; + } // don't pass the last arg - it's only recognized by the lib cache argc--; typedef GeckoProcessType (*XRE_StringToChildProcessType_t)(char*); - typedef nsresult (*XRE_InitChildProcess_t)(int, char**, GeckoProcessType); + typedef mozglueresult (*XRE_InitChildProcess_t)(int, char**, GeckoProcessType); XRE_StringToChildProcessType_t fXRE_StringToChildProcessType = (XRE_StringToChildProcessType_t)__wrap_dlsym(xul_handle, "XRE_StringToChildProcessType"); XRE_InitChildProcess_t fXRE_InitChildProcess = (XRE_InitChildProcess_t)__wrap_dlsym(xul_handle, "XRE_InitChildProcess"); GeckoProcessType proctype = fXRE_StringToChildProcessType(argv[--argc]); - nsresult rv = fXRE_InitChildProcess(argc, argv, proctype); - if (rv != 0) - return 1; - - return 0; + return fXRE_InitChildProcess(argc, argv, proctype); }
--- a/mozglue/android/APKOpen.h +++ b/mozglue/android/APKOpen.h @@ -32,35 +32,42 @@ * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef APKOpen_h #define APKOpen_h +#include <jni.h> + #ifndef NS_EXPORT #define NS_EXPORT __attribute__ ((visibility("default"))) #endif struct mapping_info { char * name; char * file_id; uintptr_t base; size_t len; size_t offset; }; const struct mapping_info * getLibraryMapping(); +static const int SUCCESS = 0; +static const int FAILURE = 1; +void JNI_Throw(JNIEnv* jenv, const char* classname, const char* msg); + #define MAX_LIB_CACHE_ENTRIES 32 #define MAX_LIB_CACHE_NAME_LEN 32 struct lib_cache_info { char name[MAX_LIB_CACHE_NAME_LEN]; int fd; uint32_t lib_size; void* buffer; }; NS_EXPORT const struct lib_cache_info * getLibraryCache(); + #endif /* APKOpen_h */
--- a/mozglue/android/Makefile.in +++ b/mozglue/android/Makefile.in @@ -50,24 +50,47 @@ STL_FLAGS= DEFINES += \ -DANDROID_PACKAGE_NAME='"$(ANDROID_PACKAGE_NAME)"' \ $(NULL) CPPSRCS = \ nsGeckoUtils.cpp \ APKOpen.cpp \ SQLiteBridge.cpp \ + NSSBridge.cpp \ $(NULL) LOCAL_INCLUDES += -I$(DEPTH)/build LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/build LOCAL_INCLUDES += -I$(srcdir)/../linker LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/components/startup LOCAL_INCLUDES += -I$(topsrcdir)/db/sqlite3/src +LOCAL_INCLUDES += -I$(topsrcdir)/base/src +LOCAL_INCLUDES += -I$(topsrcdir)/nsprpub/lib/ds +LOCAL_INCLUDES += -I$(topsrcdir)/nsprpub/lib/libc/include +LOCAL_INCLUDES += -I$(topsrcdir)/nsprpub/pr/include +LOCAL_INCLUDES += -I$(topsrcdir)/ipc/chromium/src/base/third_party/nspr +LOCAL_INCLUDES += -I$(topsrcdir)/ipc/chromium/src +LOCAL_INCLUDES += -I$(topsrcdir)/security/nss/lib/nss +LOCAL_INCLUDES += -I$(topsrcdir)/security/nss/lib/util +LOCAL_INCLUDES += -I$(topsrcdir)/security/nss/lib/softoken +LOCAL_INCLUDES += -I$(topsrcdir)/security/nss/lib/pk11wrap +LOCAL_INCLUDES += -I$(topsrcdir)/security/nss/cmd/ecperf +LOCAL_INCLUDES += -I$(topsrcdir)/security/nss/lib/pkcs7 +LOCAL_INCLUDES += -I$(topsrcdir)/security/nss/lib/certdb +LOCAL_INCLUDES += -I$(topsrcdir)/security/nss/lib/cryptohi +LOCAL_INCLUDES += -I$(topsrcdir)/security/nss/lib/dev +LOCAL_INCLUDES += -I$(topsrcdir)/security/nss/lib/base +LOCAL_INCLUDES += -I$(topsrcdir)/security/nss/lib/pki +LOCAL_INCLUDES += -I$(topsrcdir)/security/nss/lib/smime +LOCAL_INCLUDES += -I$(topsrcdir)/security/nss/lib/freebl/ +LOCAL_INCLUDES += -I$(topsrcdir)/security/nss/lib/ssl +LOCAL_INCLUDES += -I$(topsrcdir)/security/nss/cmd/lib/ + ifdef MOZ_OLD_LINKER DEFINES += -DMOZ_OLD_LINKER LOCAL_INCLUDES += -I$(topsrcdir)/other-licenses/android ifeq ($(CPU_ARCH),arm) DEFINES += -DANDROID_ARM_LINKER endif endif
new file mode 100644 --- /dev/null +++ b/mozglue/android/NSSBridge.cpp @@ -0,0 +1,300 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <stdlib.h> +#include "dlfcn.h" +#include "NSSBridge.h" +#include "APKOpen.h" +#ifdef ANDROID +#include <jni.h> +#include <android/log.h> +#endif + +#ifndef MOZ_OLD_LINKER +#include "ElfLoader.h" +#endif + +#define DEBUG 1 + +#ifdef DEBUG +#define LOG(x...) __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", x) +#else +#define LOG(x...) printf(x); +#endif + +static bool initialized = false; + +#define NSS_WRAPPER_INT(name) name ## _t f_ ## name; +NSS_WRAPPER_INT(NSS_Initialize) +NSS_WRAPPER_INT(NSS_Shutdown) +NSS_WRAPPER_INT(SECITEM_ZfreeItem) +NSS_WRAPPER_INT(PK11SDR_Encrypt) +NSS_WRAPPER_INT(PK11SDR_Decrypt) +NSS_WRAPPER_INT(PK11_GetInternalKeySlot) +NSS_WRAPPER_INT(PK11_NeedUserInit) +NSS_WRAPPER_INT(PK11_InitPin) +NSS_WRAPPER_INT(PR_ErrorToString) +NSS_WRAPPER_INT(PR_GetError) +NSS_WRAPPER_INT(PR_Free) +NSS_WRAPPER_INT(PL_Base64Encode) +NSS_WRAPPER_INT(PL_Base64Decode) +NSS_WRAPPER_INT(PL_strfree) + +int +setup_nss_functions(void *nss_handle, + void *nspr_handle, + void *plc_handle) +{ + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "setup nss 1"); + if (nss_handle == NULL || nspr_handle == NULL || plc_handle == NULL) { + LOG("missing handle\n"); + return FAILURE; + } +#define GETFUNC(name) f_ ## name = (name ## _t) __wrap_dlsym(nss_handle, #name); \ + if (!f_ ##name) return FAILURE; + GETFUNC(NSS_Initialize); + GETFUNC(NSS_Shutdown); + GETFUNC(PK11SDR_Encrypt); + GETFUNC(PK11SDR_Decrypt); + GETFUNC(PK11_GetInternalKeySlot); + GETFUNC(PK11_NeedUserInit); + GETFUNC(PK11_InitPin); + GETFUNC(SECITEM_ZfreeItem); +#undef GETFUNC +#define NSPRFUNC(name) f_ ## name = (name ## _t) __wrap_dlsym(nspr_handle, #name); \ + if (!f_ ##name) return FAILURE; + NSPRFUNC(PR_ErrorToString); + NSPRFUNC(PR_GetError); + NSPRFUNC(PR_Free); +#undef NSPRFUNC +#define PLCFUNC(name) f_ ## name = (name ## _t) __wrap_dlsym(plc_handle, #name); \ + if (!f_ ##name) return FAILURE; + PLCFUNC(PL_Base64Encode); + PLCFUNC(PL_Base64Decode); + PLCFUNC(PL_strfree); +#undef PLCFUNC + + return SUCCESS; +} + +/* Throws the current NSS error. */ +static void +throwError(JNIEnv* jenv, const char * funcString) { + char *msg; + + PRErrorCode perr = f_PR_GetError(); + char * errString = f_PR_ErrorToString(perr, 0); + asprintf(&msg, "%s returned error %d: %s\n", funcString, perr, errString); + LOG("Throwing error: %s\n", msg); + + JNI_Throw(jenv, "java/lang/Exception", msg); + free(msg); + LOG("Error thrown\n"); +} + +extern "C" NS_EXPORT jstring JNICALL +Java_org_mozilla_gecko_NSSBridge_nativeEncrypt(JNIEnv* jenv, jclass, + jstring jPath, + jstring jValue) +{ + jstring ret = jenv->NewStringUTF(""); + + const char* path; + path = jenv->GetStringUTFChars(jPath, NULL); + + const char* value; + value = jenv->GetStringUTFChars(jValue, NULL); + + char* result; + SECStatus rv = doCrypto(jenv, path, value, &result, true); + if (rv == SECSuccess) { + ret = jenv->NewStringUTF(result); + free(result); + } + + jenv->ReleaseStringUTFChars(jValue, value); + jenv->ReleaseStringUTFChars(jPath, path); + + return ret; +} + +extern "C" NS_EXPORT jstring JNICALL +Java_org_mozilla_gecko_NSSBridge_nativeDecrypt(JNIEnv* jenv, jclass, + jstring jPath, + jstring jValue) +{ + jstring ret = jenv->NewStringUTF(""); + + const char* path; + path = jenv->GetStringUTFChars(jPath, NULL); + + const char* value; + value = jenv->GetStringUTFChars(jValue, NULL); + + char* result; + SECStatus rv = doCrypto(jenv, path, value, &result, false); + if (rv == SECSuccess) { + ret = jenv->NewStringUTF(result); + free(result); + } + + jenv->ReleaseStringUTFChars(jValue, value); + jenv->ReleaseStringUTFChars(jPath, path); + + return ret; +} + + +/* Encrypts or decrypts a string. result should be freed with free() when done */ +SECStatus +doCrypto(JNIEnv* jenv, const char *path, const char *value, char** result, bool encrypt) +{ + SECStatus rv; + PK11SlotInfo *slot; + if (!initialized) { + LOG("initialize crypto %s\n", path); + rv = f_NSS_Initialize(path, "", "", "secmod.db", NSS_INIT_NOROOTINIT); + if (rv != SECSuccess) { + throwError(jenv, "NSS_Initialize"); + return rv; + } + initialized = true; + } + + slot = f_PK11_GetInternalKeySlot(); + if (!slot) { + throwError(jenv, "PK11_GetInternalKeySlot"); + return SECFailure; + } + + if (f_PK11_NeedUserInit(slot)) { + LOG("Initializing key3.db with default blank password."); + rv = f_PK11_InitPin(slot, NULL, NULL); + if (rv != SECSuccess) { + throwError(jenv, "PK11_InitPin"); + return rv; + } + } + + SECItem request; + SECItem reply; + + reply.data = 0; + reply.len = 0; + + if (encrypt) { + LOG("encrypting %s\n", value); + request.data = (unsigned char*)value; + request.len = strlen(value); + + SECItem keyid; + keyid.data = 0; + keyid.len = 0; + rv = f_PK11SDR_Encrypt(&keyid, &request, &reply, NULL); + + if (rv != SECSuccess) { + throwError(jenv, "PK11SDR_Encrypt"); + goto done; + } + + rv = encode(reply.data, reply.len, result); + if (rv != SECSuccess) { + throwError(jenv, "encode"); + goto done; + } + LOG("encrypted %s\n", *result); + } else { + LOG("decoding %s\n", value); + rv = decode(value, &request.data, (PRInt32*)&request.len); + if (rv != SECSuccess) { + throwError(jenv, "decode"); + return rv; + } + + rv = f_PK11SDR_Decrypt(&request, &reply, NULL); + if (rv != SECSuccess) { + throwError(jenv, "PK11SDR_Decrypt"); + goto done; + } + + *result = (char *)malloc(reply.len); + (*result)[reply.len] = '\0'; + strncpy(*result, (char *)reply.data, reply.len); + //asprintf(result, "%s", (char *)reply.data); + + LOG("decoded %i letters %s\n", reply.len, *result); + free(request.data); + } + +done: + f_SECITEM_ZfreeItem(&reply, false); + return rv; +} + +/* + * Base64 encodes the data passed in. The caller must deallocate _retval using free(); + */ +SECStatus +encode(const unsigned char *data, PRInt32 dataLen, char **_retval) +{ + SECStatus rv = SECSuccess; + char *encoded = f_PL_Base64Encode((const char *)data, dataLen, NULL); + if (!encoded) + rv = SECFailure; + if (!*encoded) + rv = SECFailure; + + if (rv == SECSuccess) { + *_retval = (char *)malloc(strlen(encoded)); + strcpy(*_retval, encoded); + } + + if (encoded) { + f_PR_Free(encoded); + } + + return rv; +} + +/* + * Base64 decodes the data passed in. The caller must deallocate result using free(); + */ +SECStatus +decode(const char *data, unsigned char **result, PRInt32 *length) +{ + SECStatus rv = SECSuccess; + PRUint32 len = strlen(data); + int adjust = 0; + + /* Compute length adjustment */ + if (len > 0 && data[len-1] == '=') { + adjust++; + if (data[len-2] == '=') adjust++; + } + + char *decoded; + decoded = f_PL_Base64Decode(data, len, NULL); + if (!decoded) { + return SECFailure; + } + + LOG("xxx Decoded: %s\n", decoded); + + if (!*decoded) { + return SECFailure; + } + + *length = (len*3)/4 - adjust; + *result = (unsigned char*)malloc((size_t)len); + + if (!*result) { + rv = SECFailure; + } else { + memcpy((char*)*result, decoded, len); + } + f_PR_Free(decoded); + return rv; +} + +
new file mode 100644 --- /dev/null +++ b/mozglue/android/NSSBridge.h @@ -0,0 +1,36 @@ +#ifndef NSSBridge_h +#define NSSBridge_h + +#include "nss.h" +#include "seccomon.h" +#include "secmodt.h" +#include "secutil.h" +#include "pk11func.h" +#include <jni.h> + +int setup_nss_functions(void *nss_handle, void *nssutil_handle, void *plc_handle); + +#define NSS_WRAPPER(name, return_type, args...) \ +typedef return_type (*name ## _t)(args); \ +extern name ## _t f_ ## name; + +NSS_WRAPPER(NSS_Initialize, SECStatus, const char*, const char*, const char*, const char*, PRUint32) +NSS_WRAPPER(NSS_Shutdown, void, void) +NSS_WRAPPER(PK11SDR_Encrypt, SECStatus, SECItem *, SECItem *, SECItem *, void *) +NSS_WRAPPER(PK11SDR_Decrypt, SECStatus, SECItem *, SECItem *, void *) +NSS_WRAPPER(SECITEM_ZfreeItem, void, SECItem*, PRBool) +NSS_WRAPPER(PR_ErrorToString, char *, PRErrorCode, PRLanguageCode) +NSS_WRAPPER(PR_GetError, PRErrorCode, void) +NSS_WRAPPER(PR_Free, PRErrorCode, char *) +NSS_WRAPPER(PL_Base64Encode, char*, const char*, PRUint32, char*) +NSS_WRAPPER(PL_Base64Decode, char*, const char*, PRUint32, char*) +NSS_WRAPPER(PL_strfree, void, char*) +NSS_WRAPPER(PK11_GetInternalKeySlot, PK11SlotInfo *, void) +NSS_WRAPPER(PK11_NeedUserInit, PRBool, PK11SlotInfo *) +NSS_WRAPPER(PK11_InitPin, SECStatus, PK11SlotInfo*, const char*, const char*) + +bool setPassword(PK11SlotInfo *slot); +SECStatus doCrypto(JNIEnv* jenv, const char *path, const char *value, char** result, bool doEncrypt); +SECStatus encode(const unsigned char *data, PRInt32 dataLen, char **_retval); +SECStatus decode(const char *data, unsigned char **result, PRInt32 * _retval); +#endif /* NSS_h */
--- a/mozglue/android/SQLiteBridge.cpp +++ b/mozglue/android/SQLiteBridge.cpp @@ -97,31 +97,16 @@ static jclass stringClass; static jclass objectClass; static jclass byteBufferClass; static jclass cursorClass; static jmethodID jByteBufferAllocateDirect; static jmethodID jCursorConstructor; static jmethodID jCursorAddRow; static void -JNI_Throw(JNIEnv* jenv, const char* name, const char* msg) -{ - jclass cls = jenv->FindClass(name); - if (cls == NULL) { - LOG("Couldn't find exception class (or exception pending)\n"); - return; - } - int rc = jenv->ThrowNew(cls, msg); - if (rc < 0) { - LOG("Error throwing exception\n"); - } - jenv->DeleteLocalRef(cls); -} - -static void JNI_Setup(JNIEnv* jenv) { if (initialized) return; jclass lObjectClass = jenv->FindClass("java/lang/Object"); jclass lStringClass = jenv->FindClass("java/lang/String"); jclass lByteBufferClass = jenv->FindClass("java/nio/ByteBuffer"); jclass lCursorClass = jenv->FindClass("org/mozilla/gecko/sqlite/MatrixBlobCursor");