diff --git a/build.gradle b/build.gradle index 3f806cd7..e52ed0ac 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.0' + classpath 'com.android.tools.build:gradle:2.3.3' } } diff --git a/stetho/build.gradle b/stetho/build.gradle index 34aa743c..8ad1031f 100644 --- a/stetho/build.gradle +++ b/stetho/build.gradle @@ -19,6 +19,7 @@ dependencies { compile 'com.google.code.findbugs:jsr305:2.0.1' compile 'com.android.support:appcompat-v7:23.0.1' // optional + compile 'net.zetetic:android-database-sqlcipher:3.5.7@aar' testCompile 'junit:junit:4.12' testCompile('org.robolectric:robolectric:2.4') { diff --git a/stetho/src/main/java/com/facebook/stetho/Stetho.java b/stetho/src/main/java/com/facebook/stetho/Stetho.java index 592c7ccd..4ca29117 100644 --- a/stetho/src/main/java/com/facebook/stetho/Stetho.java +++ b/stetho/src/main/java/com/facebook/stetho/Stetho.java @@ -82,6 +82,7 @@ * the {@code stetho-sample} for more information. */ public class Stetho { + public static String password = ""; private Stetho() { } @@ -101,7 +102,8 @@ public static InitializerBuilder newInitializerBuilder(Context context) { * first socket connection is received, allowing this to be safely used for debug builds on * even low-end hardware without noticeably affecting performance. */ - public static void initializeWithDefaults(final Context context) { + public static void initializeWithDefaults(final Context context, String password) { + Stetho.password = password; initialize(new Initializer(context) { @Override protected Iterable getDumperPlugins() { diff --git a/stetho/src/main/java/com/facebook/stetho/inspector/database/DatabaseConnectionProvider.java b/stetho/src/main/java/com/facebook/stetho/inspector/database/DatabaseConnectionProvider.java index 7f19d81e..def9c875 100644 --- a/stetho/src/main/java/com/facebook/stetho/inspector/database/DatabaseConnectionProvider.java +++ b/stetho/src/main/java/com/facebook/stetho/inspector/database/DatabaseConnectionProvider.java @@ -9,7 +9,8 @@ package com.facebook.stetho.inspector.database; -import android.database.sqlite.SQLiteDatabase; +//import android.database.sqlite.SQLiteDatabase; +import net.sqlcipher.database.SQLiteDatabase; import android.database.sqlite.SQLiteException; import java.io.File; diff --git a/stetho/src/main/java/com/facebook/stetho/inspector/database/DefaultDatabaseConnectionProvider.java b/stetho/src/main/java/com/facebook/stetho/inspector/database/DefaultDatabaseConnectionProvider.java index 103218a1..9f9df39c 100644 --- a/stetho/src/main/java/com/facebook/stetho/inspector/database/DefaultDatabaseConnectionProvider.java +++ b/stetho/src/main/java/com/facebook/stetho/inspector/database/DefaultDatabaseConnectionProvider.java @@ -9,13 +9,16 @@ package com.facebook.stetho.inspector.database; -import android.database.sqlite.SQLiteDatabase; +//import android.database.sqlite.SQLiteDatabase; +import net.sqlcipher.database.SQLiteDatabase; import android.database.sqlite.SQLiteException; import com.facebook.stetho.inspector.database.SQLiteDatabaseCompat.SQLiteOpenOptions; import java.io.File; +import static com.facebook.stetho.Stetho.password; + /** * Opens the requested database using * {@link SQLiteDatabase#openDatabase(String, SQLiteDatabase.CursorFactory, int)} directly. @@ -62,7 +65,7 @@ protected SQLiteDatabase performOpen(File databaseFile, @SQLiteOpenOptions int o flags |= compatInstance.provideOpenFlags(options); SQLiteDatabase db = SQLiteDatabase.openDatabase( - databaseFile.getAbsolutePath(), + databaseFile.getAbsolutePath(), password, null /* cursorFactory */, flags); compatInstance.enableFeatures(options, db); diff --git a/stetho/src/main/java/com/facebook/stetho/inspector/database/SQLiteDatabaseCompat.java b/stetho/src/main/java/com/facebook/stetho/inspector/database/SQLiteDatabaseCompat.java index 6e1c9f55..c512cb6d 100644 --- a/stetho/src/main/java/com/facebook/stetho/inspector/database/SQLiteDatabaseCompat.java +++ b/stetho/src/main/java/com/facebook/stetho/inspector/database/SQLiteDatabaseCompat.java @@ -10,7 +10,8 @@ package com.facebook.stetho.inspector.database; import android.annotation.TargetApi; -import android.database.sqlite.SQLiteDatabase; +//import android.database.sqlite.SQLiteDatabase; +import net.sqlcipher.database.SQLiteDatabase; import android.os.Build; import android.support.annotation.IntDef; @@ -31,9 +32,10 @@ public abstract class SQLiteDatabaseCompat { private static final SQLiteDatabaseCompat sInstance; static { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - sInstance = new JellyBeanAndBeyondImpl(); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { +// sInstance = new JellyBeanAndBeyondImpl(); +// } else + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { sInstance = new HoneycombImpl(); } else { sInstance = new NoopImpl(); @@ -47,7 +49,7 @@ public static SQLiteDatabaseCompat getInstance() { public abstract int provideOpenFlags(@SQLiteOpenOptions int openOptions); public abstract void enableFeatures(@SQLiteOpenOptions int openOptions, SQLiteDatabase db); - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + /*@TargetApi(Build.VERSION_CODES.JELLY_BEAN) private static class JellyBeanAndBeyondImpl extends SQLiteDatabaseCompat { @Override public int provideOpenFlags(@SQLiteOpenOptions int openOptions) { @@ -64,9 +66,9 @@ public void enableFeatures(@SQLiteOpenOptions int openOptions, SQLiteDatabase db db.setForeignKeyConstraintsEnabled(true); } } - } + }*/ - @TargetApi(Build.VERSION_CODES.HONEYCOMB) + // @TargetApi(Build.VERSION_CODES.HONEYCOMB) private static class HoneycombImpl extends SQLiteDatabaseCompat { @Override public int provideOpenFlags(@SQLiteOpenOptions int openOptions) { @@ -76,7 +78,7 @@ public int provideOpenFlags(@SQLiteOpenOptions int openOptions) { @Override public void enableFeatures(@SQLiteOpenOptions int openOptions, SQLiteDatabase db) { if ((openOptions & ENABLE_WRITE_AHEAD_LOGGING) != 0) { - db.enableWriteAheadLogging(); + db.execSQL("PRAGMA journal_mode=WAL;"); } if ((openOptions & ENABLE_FOREIGN_KEY_CONSTRAINTS) != 0) { diff --git a/stetho/src/main/java/com/facebook/stetho/inspector/database/SqliteDatabaseDriver.java b/stetho/src/main/java/com/facebook/stetho/inspector/database/SqliteDatabaseDriver.java index 75b80076..813834ba 100644 --- a/stetho/src/main/java/com/facebook/stetho/inspector/database/SqliteDatabaseDriver.java +++ b/stetho/src/main/java/com/facebook/stetho/inspector/database/SqliteDatabaseDriver.java @@ -12,9 +12,12 @@ import android.annotation.TargetApi; import android.content.Context; import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteException; -import android.database.sqlite.SQLiteStatement; +//import android.database.sqlite.SQLiteDatabase; +import net.sqlcipher.database.SQLiteDatabase; +import net.sqlcipher.database.SQLiteException; +import net.sqlcipher.database.SQLiteStatement; +//import android.database.sqlite.SQLiteException; +//import android.database.sqlite.SQLiteStatement; import com.facebook.stetho.common.Util; import com.facebook.stetho.inspector.protocol.module.Database; @@ -57,6 +60,7 @@ public SqliteDatabaseDriver(Context context) { context, new DefaultDatabaseFilesProvider(context), new DefaultDatabaseConnectionProvider()); + SQLiteDatabase.loadLibs(context); } /** diff --git a/stetho/src/main/java/com/facebook/stetho/inspector/network/NetworkEventReporterImpl.java b/stetho/src/main/java/com/facebook/stetho/inspector/network/NetworkEventReporterImpl.java index 5b0a5213..4e6690f0 100644 --- a/stetho/src/main/java/com/facebook/stetho/inspector/network/NetworkEventReporterImpl.java +++ b/stetho/src/main/java/com/facebook/stetho/inspector/network/NetworkEventReporterImpl.java @@ -10,22 +10,31 @@ package com.facebook.stetho.inspector.network; import android.os.SystemClock; + import com.facebook.stetho.common.Utf8Charset; import com.facebook.stetho.inspector.console.CLog; import com.facebook.stetho.inspector.protocol.module.Console; import com.facebook.stetho.inspector.protocol.module.Network; import com.facebook.stetho.inspector.protocol.module.Page; + import org.json.JSONException; import org.json.JSONObject; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CodingErrorAction; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicInteger; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * Implementation of {@link NetworkEventReporter} which allows callers to inform the Stetho * system of network traffic. Callers can safely eagerly access this class and store a @@ -39,6 +48,8 @@ public class NetworkEventReporterImpl implements NetworkEventReporter { private static NetworkEventReporter sInstance; + private static final CharsetDecoder decoder = Charset.forName(Utf8Charset.NAME).newDecoder(); + private NetworkEventReporterImpl() { } @@ -49,6 +60,8 @@ private NetworkEventReporterImpl() { public static synchronized NetworkEventReporter get() { if (sInstance == null) { sInstance = new NetworkEventReporterImpl(); + decoder.onUnmappableCharacter(CodingErrorAction.REPORT); + decoder.onMalformedInput(CodingErrorAction.REPORT); } return sInstance; } @@ -115,15 +128,29 @@ private static String readBodyAsString( InspectorRequest request) { try { byte[] body = request.body(); - if (body != null) { - return new String(body, Utf8Charset.INSTANCE); + if (body == null || body.length == 0) { + return ""; + } + try { + CharBuffer charBuffer = decoder.decode(ByteBuffer.wrap(body)); + return charBuffer.toString(); + } catch (CharacterCodingException e) { + String logMessage = "Charset in POST/PUT is not UTF-8. Data (length:"+ body.length + +") cannot be represented as a string. "; + CLog.writeToConsole( + peerManager, + Console.MessageLevel.WARNING, + Console.MessageSource.NETWORK, + logMessage + e); + return logMessage; } } catch (IOException | OutOfMemoryError e) { CLog.writeToConsole( - peerManager, - Console.MessageLevel.WARNING, - Console.MessageSource.NETWORK, - "Could not reproduce POST body: " + e); + peerManager, + Console.MessageLevel.WARNING, + Console.MessageSource.NETWORK, + "Could not reproduce POST/PUT body: " + e); + } return null; }