Skip to content

Commit

Permalink
一些简单的升级和清理
Browse files Browse the repository at this point in the history
  • Loading branch information
Em3rs0n authored and Em3rs0n committed Nov 23, 2018
1 parent d0d3a08 commit 6613c8e
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 66 deletions.
23 changes: 10 additions & 13 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
// 重复添加同样的依赖,以保证Spellbook能够独立编译
buildscript {
ext {
dokka_version = '0.9.15'
kotlin_version = '1.2.41'
dokka_version = '0.9.17'
kotlin_version = '1.3.10'
}
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.2'
classpath 'com.android.tools.build:gradle:3.2.1'
classpath "org.jetbrains.dokka:dokka-android-gradle-plugin:$dokka_version"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
Expand All @@ -26,14 +26,14 @@ kotlin {
}

android {
compileSdkVersion 27
compileSdkVersion 28
defaultConfig {
minSdkVersion 19
targetSdkVersion 27
targetSdkVersion 28
versionCode 1
versionName "1.0"

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
Expand Down Expand Up @@ -67,18 +67,15 @@ repositories {
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
androidTestImplementation 'androidx.test:runner:1.1.0'
androidTestImplementation 'androidx.test.ext:junit:1.0.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'

//noinspection GradleDependency
compileOnly 'de.robv.android.xposed:api:53'
compileOnly 'de.robv.android.xposed:api:53:sources'

implementation 'net.dongliu:apk-parser:2.5.3'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.21'
api "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}

dokka {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package com.gh0u1l5.wechatmagician.spellbook

import android.content.Context
import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.gh0u1l5.wechatmagician.spellbook.base.Version
import com.gh0u1l5.wechatmagician.spellbook.mirror.MirrorClasses
import com.gh0u1l5.wechatmagician.spellbook.mirror.MirrorFields
import com.gh0u1l5.wechatmagician.spellbook.mirror.MirrorMethods
import com.gh0u1l5.wechatmagician.spellbook.util.FileUtil
import com.gh0u1l5.wechatmagician.spellbook.util.MirrorUtil.clearUnitTestLazyFields
import com.gh0u1l5.wechatmagician.spellbook.util.MirrorUtil.generateReportWithForceEval
import com.gh0u1l5.wechatmagician.spellbook.util.MirrorUtil
import com.gh0u1l5.wechatmagician.spellbook.util.ReflectionUtil
import dalvik.system.PathClassLoader
import net.dongliu.apk.parser.ApkFile
Expand All @@ -31,15 +30,15 @@ class MirrorUnitTest {
private var context: Context? = null

@Before fun initialize() {
context = InstrumentationRegistry.getContext()
context = InstrumentationRegistry.getInstrumentation().targetContext
}

private fun verifyPackage(apkPath: String) {
val cacheDir = context!!.cacheDir

val apkFile = File(cacheDir, apkPath)
try {
javaClass.classLoader.getResourceAsStream(apkPath).use {
javaClass.classLoader!!.getResourceAsStream(apkPath).use {
FileUtil.writeInputStreamToDisk(apkFile.absolutePath, it)
}
} catch (t: Throwable) {
Expand All @@ -61,9 +60,10 @@ class MirrorUnitTest {
ReflectionUtil.clearClassCache()
ReflectionUtil.clearMethodCache()
objects.forEach { instance ->
clearUnitTestLazyFields(instance)
MirrorUtil.clearUnitTestLazyFields(instance)
}
generateReportWithForceEval(objects).forEach {

MirrorUtil.generateReportWithForceEval(objects).forEach {
Log.d("MirrorUnitTest", "Verified ${it.first} -> ${it.second}")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ object WechatGlobal {
/**
* A [WaitChannel] blocking all the evaluations until [WechatGlobal.init] has finished.
*/
private val initializeChannel = WaitChannel()
val initializeChannel = WaitChannel()

/**
* A [Version] holding the version of current Wechat.
Expand Down Expand Up @@ -62,7 +62,7 @@ object WechatGlobal {
* @param initializer the callback that actually initialize the lazy object.
* @return a lazy object that can be used for lazy evaluation.
*/
fun <T> wxLazy(name: String, initializer: () -> T?): Lazy<T> {
inline fun <T> wxLazy(name: String, crossinline initializer: () -> T?): Lazy<T> {
return if (wxUnitTestMode) {
UnitTestLazyImpl {
initializer() ?: throw Error("Failed to evaluate $name")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,27 @@ import kotlin.concurrent.thread
*/
object BasicUtil {
/**
* trySilently will execute a callback and ignore any thrown exceptions.
* Executes a callback and ignore any thrown exceptions.
*/
fun <T: Any>trySilently(func: () -> T?): T? {
inline fun <T: Any>trySilently(func: () -> T?): T? {
return try { func() } catch (t: Throwable) { null }
}

/**
* tryVerbosely will execute a callback and record any thrown exceptions to the Xposed log.
* Executes a callback and record any thrown exceptions in the Xposed log.
*/
fun <T: Any>tryVerbosely(func: () -> T?): T? {
inline fun <T: Any>tryVerbosely(func: () -> T?): T? {
return try { func() } catch (t: Throwable) {
Log.e("Xposed", Log.getStackTraceString(t)); null
}
}

/**
* tryAsynchronously will execute a callback in another thread and record any thrown exceptions
* to the Xposed log.
* Executes a callback asynchronously and record any thrown exceptions in the Xposed log.
*
* Remember to handle UI operations in UI thread properly in the callback.
*/
fun tryAsynchronously(func: () -> Unit): Thread {
inline fun tryAsynchronously(crossinline func: () -> Unit): Thread {
return thread(start = true) { func() }.apply {
setUncaughtExceptionHandler { _, t ->
Log.e("Xposed", Log.getStackTraceString(t))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,26 @@ import java.util.*
*/
object FileUtil {
/**
* writeBytesToDisk creates a file and writes the given data into it.
* Creates a file and writes the given data into it.
*/
fun writeBytesToDisk(path: String, content: ByteArray) {
val file = File(path)
file.parentFile.mkdirs()
val file = File(path).also { it.parentFile.mkdirs() }
FileOutputStream(file).use {
it.write(content)
BufferedOutputStream(it).write(content)
}
}

/**
* readBytesFromDisk returns all the bytes of a binary file.
* Returns all the bytes of a binary file.
*/
fun readBytesFromDisk(path: String): ByteArray {
return FileInputStream(path).use {
it.readBytes()
BufferedInputStream(it).readBytes()
}
}

/**
* writeObjectToDisk writes a [Serializable] object onto the disk.
* Writes a [Serializable] object onto the disk.
*/
fun writeObjectToDisk(path: String, obj: Serializable) {
val out = ByteArrayOutputStream()
Expand All @@ -46,7 +45,7 @@ object FileUtil {
}

/**
* readObjectFromDisk reads a [Serializable] object from the disk.
* Reads a [Serializable] object from the disk.
*/
fun readObjectFromDisk(path: String): Any? {
val bytes = readBytesFromDisk(path)
Expand All @@ -57,28 +56,28 @@ object FileUtil {
}

/**
* writeInputStreamToDisk forward the data from a [InputStream] to a file, this is extremely
* helpful when the device has a low memory.
* Forwards the data from a [InputStream] to a file, this is extremely helpful when the device
* has a low memory.
*
* @param path the path of the destination
* @param `in` the [InputStream] that provides the data
* @param ins the [InputStream] that provides the data
* @param bufferSize default buffer size, one may set a larger number for better performance.
*/
fun writeInputStreamToDisk(path: String, `in`: InputStream, bufferSize: Int = 8192) {
fun writeInputStreamToDisk(path: String, ins: InputStream, bufferSize: Int = 8192) {
val file = File(path)
file.parentFile.mkdirs()
FileOutputStream(file).use {
val buffer = ByteArray(bufferSize)
var length = `in`.read(buffer)
var length = ins.read(buffer)
while (length != -1) {
it.write(buffer, 0, length)
length = `in`.read(buffer)
length = ins.read(buffer)
}
}
}

/**
* writeBitmapToDisk saves a given [Bitmap] object to disk.
* Saves a given [Bitmap] object to disk.
*/
fun writeBitmapToDisk(path: String, bitmap: Bitmap) {
val out = ByteArrayOutputStream()
Expand All @@ -87,9 +86,9 @@ object FileUtil {
}

/**
* writeOnce ensures that the write callback will only be executed once after start up.
* Ensures that the write callback will only be executed once after start up.
*/
fun writeOnce(path: String, writeCallback: (String) -> Unit) {
inline fun writeOnce(path: String, writeCallback: (String) -> Unit) {
val file = File(path)
if (!file.exists()) {
writeCallback(path)
Expand All @@ -103,13 +102,15 @@ object FileUtil {
}

/**
* createTimeTag returns the current time in a simple format as a time tag.
* Returns the current time in a simple format as a time tag.
*/
private val formatter = SimpleDateFormat("yyyy-MM-dd-HHmmss", Locale.getDefault())
private val formatter: SimpleDateFormat
get() = SimpleDateFormat("yyyy-MM-dd-HHmmss", Locale.getDefault())

fun createTimeTag(): String = formatter.format(Calendar.getInstance().time)

/**
* notifyNewMediaFile notifies all the apps that there is a new media file to scan.
* Notifies all the apps that there is a new media file to scan.
*/
fun notifyNewMediaFile(path: String, context: Context?) {
val intent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@ object MirrorUtil {
}.flatten().sortedBy { it.first }
}

/**
* WARNING: 仅供单元测试使用
*/
fun clearUnitTestLazyFields(instance: Any) {
instance::class.java.declaredFields.forEach { field ->
if (Lazy::class.java.isAssignableFrom(field.type)) {
field.isAccessible = true
val lazyObject = field.get(instance)
if (lazyObject is WechatGlobal.UnitTestLazyImpl<*>) {
lazyObject.refresh()
}
}
}
}

/**
* WARNING: 仅供单元测试使用
*/
fun generateReportWithForceEval(instances: List<Any>): List<Pair<String, String>> {
return instances.map { instance ->
collectFields(instance).map {
Expand All @@ -38,16 +56,4 @@ object MirrorUtil {
}
}.flatten().sortedBy { it.first }
}

@JvmStatic fun clearUnitTestLazyFields(instance: Any) {
instance::class.java.declaredFields.forEach { field ->
if (Lazy::class.java.isAssignableFrom(field.type)) {
field.isAccessible = true
val lazyObject = field.get(instance)
if (lazyObject is WechatGlobal.UnitTestLazyImpl<*>) {
lazyObject.refresh()
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ object XposedUtil {
private val hookerHandler: Handler = Handler(hookerHandlerThread.looper)

/**
* tryHook hooks the functions using the suitable strategies for different API levels. NOTE: for
* Android 7.X or later, multi-thread causes unexpected crashes with WeXposed, so we drop this
* feature for now.
* Hooks the functions using the suitable strategies for different API levels.
*
* NOTE: for Android 7.X or later, multi-thread causes unexpected crashes with WeXposed, so we
* drop this feature for now.
*
* @param hook the callback function that actually hooks the functions using Xposed.
*/
Expand All @@ -38,7 +39,7 @@ object XposedUtil {
}

/**
* postHooker posts the hooker to [hookerHandlerThread] for further process.
* Posts the hooker to [hookerHandlerThread] for further process.
*/
fun postHooker(hooker: Hooker) {
hookerHandler.post {
Expand Down

0 comments on commit 6613c8e

Please sign in to comment.