Skip to content

Commit 5ae0d67

Browse files
authored
Merge pull request #14 from MiPushFramework/canary
Canary
2 parents a0a2341 + 02bdf0d commit 5ae0d67

File tree

7 files changed

+186
-60
lines changed

7 files changed

+186
-60
lines changed

app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ buildscript {
55
maven { url "https://plugins.gradle.org/m2/" }
66
}
77
dependencies {
8-
classpath 'com.android.tools.build:gradle:3.4.0-alpha10'
8+
classpath 'com.android.tools.build:gradle:3.5.0-alpha01'
99
classpath 'com.google.android.gms:oss-licenses-plugin:0.9.4'
1010
classpath 'io.fabric.tools:gradle:1.27.0'
1111
classpath "com.github.triplet.gradle:play-publisher:2.0.0-rc2"
@@ -150,5 +150,5 @@ dependencies {
150150
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
151151
kapt 'com.android.databinding:compiler:3.1.4'
152152
// Condom
153-
implementation 'com.oasisfeng.condom:library:2.2.0'
153+
implementation 'com.oasisfeng.condom:library:2.3.1'
154154
}

app/proguard-rules.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# MiPush
2+
-keep class moe.yuuta.mipushtester.push.InternalPushReceiver {*;}
23
-keep class moe.yuuta.mipushtester.push.PushReceiver {*;}
34
-dontwarn com.xiaomi.push.**
45
-dontwarn com.xiaomi.mipush.**

app/src/main/kotlin/MainFragment.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import moe.yuuta.mipushtester.utils.Utils
3535
import retrofit2.Call
3636
import retrofit2.Callback
3737
import retrofit2.Response
38+
import java.io.File
3839

3940
class MainFragment : Fragment(), MainFragmentUIHandler {
4041
private val logger = XLog.tag(MainFragment::class.simpleName).build()
@@ -194,6 +195,9 @@ class MainFragment : Fragment(), MainFragmentUIHandler {
194195
requireContext().getSharedPreferences("mipush", MODE_PRIVATE).edit().clear().commit()
195196
requireContext().getSharedPreferences("mipush_extra", MODE_PRIVATE).edit().clear().commit()
196197
requireContext().getSharedPreferences("mipush_oc", MODE_PRIVATE).edit().clear().commit()
198+
File(requireContext().filesDir.absolutePath + "/" + "mipush_region").delete()
199+
File(requireContext().filesDir.absolutePath + "/" + "mipush_region.lock").delete()
200+
requireContext().getDatabasePath("geofencing").delete()
197201
Toast.makeText(requireContext(), R.string.reset_toast, Toast.LENGTH_LONG).show()
198202

199203
Utils.restart(requireContext())
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package moe.yuuta.mipushtester.push
2+
3+
import android.content.Context
4+
import android.content.Intent
5+
import android.os.Handler
6+
import android.os.Looper
7+
import android.widget.Toast
8+
import com.elvishew.xlog.XLog
9+
import com.xiaomi.mipush.sdk.*
10+
import moe.yuuta.mipushtester.R
11+
import moe.yuuta.mipushtester.push.internal.PushSdkWrapper
12+
import moe.yuuta.mipushtester.status.RegistrationStatus
13+
14+
class InternalPushReceiver : PushMessageReceiver() {
15+
private val logger = XLog.tag(InternalPushReceiver::class.simpleName).build()
16+
17+
override fun onReceivePassThroughMessage(context: Context, miPushMessage: MiPushMessage) {
18+
Handler(Looper.getMainLooper()).post(object : Runnable {
19+
override fun run() {
20+
Toast.makeText(context.applicationContext, context.getString(R.string.push_receiver_pass_through_received,
21+
miPushMessage.messageId), Toast.LENGTH_SHORT).show()
22+
}
23+
})
24+
context.startActivity(Intent(context, MessageDetailActivity::class.java)
25+
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
26+
.putExtra(PushMessageHelper.KEY_MESSAGE, miPushMessage))
27+
}
28+
29+
override fun onCommandResult(context: Context, message: MiPushCommandMessage) {
30+
val command = message.command
31+
logger.i("Handle command: $command, code: ${message.resultCode}")
32+
val commandHumanValue: String
33+
commandHumanValue = when(command) {
34+
PushSdkWrapper.COMMAND_REGISTER -> {
35+
RegistrationStatus.get(context).registered.set(message.resultCode == (ErrorCode.SUCCESS.toLong()))
36+
context.getString(R.string.command_register)
37+
}
38+
else ->
39+
message.command.toString()
40+
}
41+
if (message.resultCode != ErrorCode.SUCCESS.toLong()) {
42+
logger.e("Received error code ${message.resultCode}")
43+
Handler(Looper.getMainLooper()).post(object : Runnable {
44+
override fun run() {
45+
Toast.makeText(context.applicationContext, context.getString(R.string.push_receiver_command_error,
46+
commandHumanValue, message.resultCode.toString()), Toast.LENGTH_LONG).show()
47+
}
48+
})
49+
}
50+
}
51+
}
Lines changed: 17 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,27 @@
11
package moe.yuuta.mipushtester.push
22

3+
import android.content.BroadcastReceiver
34
import android.content.Context
45
import android.content.Intent
5-
import android.os.Handler
6-
import android.os.Looper
7-
import android.widget.Toast
86
import com.elvishew.xlog.XLog
9-
import com.xiaomi.mipush.sdk.*
10-
import moe.yuuta.mipushtester.R
11-
import moe.yuuta.mipushtester.push.internal.PushSdkWrapper
12-
import moe.yuuta.mipushtester.status.RegistrationStatus
7+
import moe.yuuta.mipushtester.utils.Utils
138

14-
class PushReceiver : PushMessageReceiver() {
9+
/**
10+
* A wrapper of InternalPushReceiver which records the income Intent.
11+
* InternalPushReceiver should not be declared in manifest.
12+
* To pass the manifest check, we enable an empty receiver (StubPushReceiver) at first, then
13+
* register push, finally disable it and re-enable this receiver.
14+
*/
15+
class PushReceiver : BroadcastReceiver() {
1516
private val logger = XLog.tag(PushReceiver::class.simpleName).build()
1617

17-
override fun onReceivePassThroughMessage(context: Context, miPushMessage: MiPushMessage) {
18-
Handler(Looper.getMainLooper()).post(object : Runnable {
19-
override fun run() {
20-
Toast.makeText(context.applicationContext, context.getString(R.string.push_receiver_pass_through_received,
21-
miPushMessage.messageId), Toast.LENGTH_SHORT).show()
22-
}
23-
})
24-
context.startActivity(Intent(context, MessageDetailActivity::class.java)
25-
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
26-
.putExtra(PushMessageHelper.KEY_MESSAGE, miPushMessage))
27-
}
28-
29-
override fun onCommandResult(context: Context, message: MiPushCommandMessage) {
30-
val command = message.command
31-
logger.i("Handle command: $command, code: ${message.resultCode}")
32-
val commandHumanValue: String
33-
commandHumanValue = when(command) {
34-
PushSdkWrapper.COMMAND_REGISTER -> {
35-
RegistrationStatus.get(context).registered.set(message.resultCode == (ErrorCode.SUCCESS.toLong()))
36-
context.getString(R.string.command_register)
37-
}
38-
else ->
39-
message.command.toString()
40-
}
41-
if (message.resultCode != ErrorCode.SUCCESS.toLong()) {
42-
logger.e("Received error code ${message.resultCode}")
43-
Handler(Looper.getMainLooper()).post(object : Runnable {
44-
override fun run() {
45-
Toast.makeText(context.applicationContext, context.getString(R.string.push_receiver_command_error,
46-
commandHumanValue, message.resultCode.toString()), Toast.LENGTH_LONG).show()
47-
}
48-
})
18+
override fun onReceive(p0: Context, p1: Intent) {
19+
logger.i("Received $p1")
20+
try {
21+
logger.json(Utils.dumpIntent(p1))
22+
} catch (e: Throwable) {
23+
logger.e("Unable to dump intent", e)
4924
}
25+
InternalPushReceiver().onReceive(p0, p1)
5026
}
51-
}
27+
}

app/src/main/kotlin/push/internal/PushSdkWrapper.kt

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package moe.yuuta.mipushtester.push.internal
22

3+
import android.annotation.SuppressLint
34
import android.app.Application
45
import android.content.ComponentName
56
import android.content.Context
67
import android.content.Intent
8+
import android.content.pm.ActivityInfo
79
import android.content.pm.PackageManager
10+
import android.content.pm.ResolveInfo
811
import androidx.annotation.NonNull
912
import com.oasisfeng.condom.*
1013
import com.xiaomi.mipush.sdk.MiPushClient
14+
import moe.yuuta.mipushtester.push.InternalPushReceiver
1115

1216
/**
1317
* The utils class to operate MiPushClient and other third-party components.
@@ -31,8 +35,14 @@ object PushSdkWrapper {
3135
CondomContext.wrap(context.applicationContext, "MiPushSDK", createOptions()).applicationContext as Application
3236

3337
fun isDisabled(@NonNull context: Context): Boolean =
34-
(context.packageManager.getComponentEnabledSetting(ComponentName(context, CoreProvider::class.java))
35-
== PackageManager.COMPONENT_ENABLED_STATE_DISABLED)
38+
when (context.packageManager.getComponentEnabledSetting(ComponentName(context, CoreProvider::class.java))) {
39+
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT -> true
40+
PackageManager.COMPONENT_ENABLED_STATE_DISABLED -> true
41+
PackageManager.COMPONENT_ENABLED_STATE_ENABLED -> false
42+
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED -> true
43+
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER -> true
44+
else -> true
45+
}
3646

3747
private fun wrapContext(@NonNull context: Context): Application =
3848
if (isDisabled(context))
@@ -45,23 +55,31 @@ object PushSdkWrapper {
4555
.preventBroadcastToBackgroundPackages(false)
4656
.preventServiceInBackgroundPackages(false)
4757
.setDryRun(false)
48-
.setOutboundJudge(object : OutboundJudge{
49-
override fun shouldAllow(type: OutboundType, intent: Intent?, target_package: String): Boolean {
50-
// Always allow to get hte realist results
51-
return true
58+
.setPackageManagerFactory { base, downstream ->
59+
object : PackageManagerWrapper(downstream) {
60+
@SuppressLint("RestrictedApi")
61+
override fun queryBroadcastReceivers(intent: Intent, flags: Int): MutableList<ResolveInfo> {
62+
if ((intent.action ?: "").equals("com.xiaomi.mipush.RECEIVE_MESSAGE") &&
63+
(intent.`package` ?: "").equals(base.packageName)) {
64+
val resolveInfo: ResolveInfo = ResolveInfo()
65+
val activityInfo: ActivityInfo = ActivityInfo()
66+
resolveInfo.activityInfo = activityInfo
67+
activityInfo.name = InternalPushReceiver::class.java.name
68+
return mutableListOf(resolveInfo)
69+
}
70+
return super.queryBroadcastReceivers(intent, flags)
71+
}
5272
}
53-
})
54-
.addKit(object : CondomKit{
55-
override fun onRegister(registry: CondomKit.CondomKitRegistry) {
56-
registry.addPermissionSpoof(android.Manifest.permission.INTERNET)
57-
registry.addPermissionSpoof(android.Manifest.permission.ACCESS_NETWORK_STATE)
58-
registry.addPermissionSpoof(android.Manifest.permission.ACCESS_WIFI_STATE)
59-
registry.addPermissionSpoof(android.Manifest.permission.READ_PHONE_STATE)
60-
registry.addPermissionSpoof(android.Manifest.permission.GET_TASKS)
61-
registry.addPermissionSpoof(android.Manifest.permission.VIBRATE)
62-
registry.addPermissionSpoof("${BuildConfig.APPLICATION_ID}.permission.MIPUSH_RECEIVE")
73+
}
74+
.addKit {
75+
it.addPermissionSpoof(android.Manifest.permission.INTERNET)
76+
it.addPermissionSpoof(android.Manifest.permission.ACCESS_NETWORK_STATE)
77+
it.addPermissionSpoof(android.Manifest.permission.ACCESS_WIFI_STATE)
78+
it.addPermissionSpoof(android.Manifest.permission.READ_PHONE_STATE)
79+
it.addPermissionSpoof(android.Manifest.permission.GET_TASKS)
80+
it.addPermissionSpoof(android.Manifest.permission.VIBRATE)
81+
it.addPermissionSpoof("${BuildConfig.APPLICATION_ID}.permission.MIPUSH_RECEIVE")
6382
}
64-
})
6583

6684
/**
6785
* Set up Condom and other necessary things.

app/src/main/kotlin/utils/Utils.kt

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@ import android.app.AlarmManager
44
import android.app.PendingIntent
55
import android.content.Context
66
import android.content.Intent
7+
import android.os.Bundle
78
import android.os.Handler
89
import android.os.Looper
910
import android.os.Process
11+
import com.google.gson.Gson
12+
import com.google.gson.JsonArray
13+
import com.google.gson.JsonObject
1014
import moe.yuuta.mipushtester.MainActivity
15+
import java.lang.reflect.Field
16+
import java.lang.reflect.Modifier
1117

1218
object Utils {
1319
fun restart(context: Context) {
@@ -23,4 +29,74 @@ object Utils {
2329
Runtime.getRuntime().exit(0)
2430
}, 100)
2531
}
32+
33+
fun dumpIntent(intent: Intent): String {
34+
val trackMs: Long = System.currentTimeMillis()
35+
val rootJson: JsonObject = JsonObject()
36+
rootJson.addProperty("action", intent.action)
37+
val categoriesJson: JsonArray = JsonArray()
38+
if (intent.categories != null) {
39+
for (category in intent.categories) {
40+
categoriesJson.add(category)
41+
}
42+
}
43+
rootJson.add("categories", categoriesJson)
44+
rootJson.addProperty("clip_data_has", intent.clipData != null)
45+
val componentJson: JsonObject = JsonObject()
46+
componentJson.addProperty("package_name", intent.component?.packageName ?: "(Null)")
47+
componentJson.addProperty("class_name", intent.component?.className ?: "(Null)")
48+
rootJson.add("component", componentJson)
49+
rootJson.addProperty("data_string", intent.dataString)
50+
rootJson.addProperty("flag_raw", intent.flags)
51+
val flagFields: Array<Field>? = Intent::class.java.declaredFields
52+
val flagsJson: JsonArray = JsonArray()
53+
if (flagFields != null) {
54+
for (flag in flagFields) {
55+
if (Modifier.isFinal(flag.modifiers) &&
56+
Modifier.isPublic(flag.modifiers) &&
57+
Modifier.isStatic(flag.modifiers) &&
58+
flag.name.startsWith("FLAG_")) {
59+
try {
60+
val value: Int = flag.get(null) as Int
61+
if ((intent.flags and value) != 0) {
62+
flagsJson.add(flag.name)
63+
}
64+
} catch (ignored: Exception) {}
65+
}
66+
}
67+
}
68+
rootJson.add("flags", flagsJson)
69+
rootJson.addProperty("package", intent.`package`)
70+
rootJson.addProperty("scheme", intent.scheme)
71+
rootJson.addProperty("selector_has", intent.selector != null)
72+
rootJson.addProperty("source_bounds_has", intent.sourceBounds != null)
73+
rootJson.addProperty("type", intent.type)
74+
rootJson.add("extras", dumpExtras(intent.extras))
75+
if (intent.hasExtra("mipush_payload")) {
76+
val payload: ByteArray = intent.getByteArrayExtra("mipush_payload")
77+
// TODO: Deserialize payload
78+
val payloadArray: JsonArray = JsonArray()
79+
for (byte in payload) {
80+
payloadArray.add(byte)
81+
}
82+
rootJson.add("payload", payloadArray)
83+
}
84+
rootJson.addProperty("took", System.currentTimeMillis() - trackMs)
85+
return Gson().toJson(rootJson)
86+
}
87+
88+
fun dumpExtras(bundle: Bundle?): JsonArray {
89+
val extrasJson: JsonArray = JsonArray()
90+
if (bundle != null) {
91+
for (key in bundle.keySet()) {
92+
val value = bundle.get(key)
93+
val obj: JsonObject = JsonObject()
94+
obj.addProperty("value", value?.toString())
95+
obj.addProperty("key", key)
96+
obj.addProperty("value_type", value.javaClass.name)
97+
extrasJson.add(obj)
98+
}
99+
}
100+
return extrasJson
101+
}
26102
}

0 commit comments

Comments
 (0)