Skip to content

Commit f32f189

Browse files
committed
INTEGRATE: log event flow
* upgrade_sdk_to_3_7_9: feat: log event flow feat: implement MiPushEventListener.transferToServer feat: implement MiPushEventListener.receiveFromApplication feat: implement MiPushEventListener.transferToApplication feat: implement MiPushEventListener.transferToApplication refactor: create generic packToContainer method refactor: move shouldSendBroadcast Hook to class MethodHooker feat: implement MiPushEventListener.receiveFromServer feat: allow containers without metainfo to be mocked build(common): remove useless dependency build: exclude test classes in AspectJX configuration
2 parents 614b401 + bcd65ec commit f32f189

12 files changed

Lines changed: 328 additions & 21 deletions

File tree

common/build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ android.libraryVariants.all { variant ->
3838
}
3939

4040
dependencies {
41-
implementation fileTree(dir: 'libs', include: ['*.jar'])
4241
implementation 'androidx.appcompat:appcompat:1.0.0'
4342

4443
testImplementation 'junit:junit:4.13.2'

mipush_hook/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ android {
3636
// 移除kotlin相关,编译错误和提升速度
3737
exclude("kotlin.jvm", "kotlin.internal")
3838
exclude("kotlinx.coroutines.internal", "kotlinx.coroutines.android")
39+
exclude("test.", "Test")
3940
ajcArgs("-inpath", mipushLib.path)
4041
debug = true
4142
}

push/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ android {
6363
exclude 'kotlin.jvm', 'kotlin.internal'
6464
exclude 'kotlinx.coroutines.internal', 'kotlinx.coroutines.android'
6565
exclude 'top.trumeet'
66+
exclude 'test.', 'Test'
6667
debug = true
6768
}
6869

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package test.com.nihility;
2+
3+
import static com.xiaomi.push.service.MIPushEventProcessor.postProcessMIPushMessage;
4+
import static com.xiaomi.push.service.PullAllApplicationDataFromServerJob.getPullAction;
5+
import static org.mockito.Mockito.verify;
6+
7+
import android.content.Context;
8+
import android.content.Intent;
9+
10+
import androidx.test.core.app.ApplicationProvider;
11+
12+
import com.elvishew.xlog.XLog;
13+
import com.nihility.MethodHooker;
14+
import com.nihility.MiPushEventListener;
15+
import com.nihility.XMPushUtils;
16+
import com.nihility.utils.MockMIPushMessage;
17+
import com.xiaomi.channel.commonutils.reflect.JavaCalls;
18+
import com.xiaomi.push.service.MIPushEventProcessor;
19+
import com.xiaomi.push.service.MIPushNotificationHelper;
20+
import com.xiaomi.push.service.XMPushService;
21+
import com.xiaomi.xmpush.thrift.PushMetaInfo;
22+
import com.xiaomi.xmpush.thrift.XmPushActionContainer;
23+
24+
import org.aspectj.lang.ProceedingJoinPoint;
25+
import org.junit.After;
26+
import org.junit.Before;
27+
import org.junit.Test;
28+
import org.junit.runner.RunWith;
29+
import org.mockito.Mock;
30+
import org.mockito.junit.MockitoJUnitRunner;
31+
32+
@RunWith(MockitoJUnitRunner.class)
33+
public class MiPushEventListenerTest {
34+
@Mock
35+
MiPushEventListener eventListener;
36+
XmPushActionContainer container = XMPushUtils.packToContainer(getPullAction("appId"), "");
37+
38+
@Before
39+
public void setup() {
40+
XLog.init();
41+
MiPushEventListener.setInstance(eventListener);
42+
MethodHooker.setInstance(new MethodHooker() {
43+
@Override
44+
public boolean shouldSendBroadcast(ProceedingJoinPoint joinPoint, XMPushService pushService, String packageName, XmPushActionContainer container, PushMetaInfo metaInfo) throws Throwable {
45+
return true;
46+
}
47+
});
48+
}
49+
50+
@After
51+
public void teardown() {
52+
MiPushEventListener.setInstance(null);
53+
MethodHooker.setInstance(null);
54+
}
55+
56+
@Test
57+
public void triggerReceiveFromServerAtProcessMIPushMessage() {
58+
try {
59+
MockMIPushMessage.invokeProcessMiPushMessage(null, container);
60+
} catch (Throwable ignored) {
61+
}
62+
63+
verify(eventListener).receiveFromServer(container);
64+
}
65+
66+
@Test
67+
public void triggerTransferToApplicationAtPostProcessMIPushMessageSendBroadcast() {
68+
XMPushService xmPushService = new XMPushService() {
69+
@Override
70+
public Context getApplicationContext() {
71+
return ApplicationProvider.getApplicationContext();
72+
}
73+
74+
@Override
75+
public Context getBaseContext() {
76+
return ApplicationProvider.getApplicationContext();
77+
}
78+
};
79+
byte[] payload = XMPushUtils.packToBytes(container);
80+
Intent intent = MIPushEventProcessor.buildIntent(payload, 0);
81+
82+
postProcessMIPushMessage(xmPushService, null, payload, intent);
83+
84+
verify(eventListener).transferToApplication(container);
85+
}
86+
87+
@Test
88+
public void triggerTransferToApplicationAtNotifyPushMessage() {
89+
try {
90+
MIPushNotificationHelper.notifyPushMessage(null, container, null);
91+
} catch (Throwable ignored) {
92+
}
93+
94+
verify(eventListener).transferToApplication(container);
95+
}
96+
97+
@Test
98+
public void triggerReceiveFromApplicationAtXMPushServiceOnStart() {
99+
XMPushService xmPushService = new XMPushService() {
100+
@Override
101+
public void executeJob(Job job) {
102+
}
103+
};
104+
Intent intent = new Intent("test");
105+
106+
xmPushService.onStart(intent, 1);
107+
108+
verify(eventListener).receiveFromApplication(intent);
109+
}
110+
111+
@Test
112+
public void triggerTransferToServerAtSendMessage() {
113+
XMPushService xmPushService = new XMPushService();
114+
115+
{
116+
Intent intent = new Intent("test");
117+
118+
JavaCalls.callMethod(xmPushService, "sendMessage", intent);
119+
120+
verify(eventListener).transferToServer(intent);
121+
}
122+
{
123+
Intent intent = new Intent("qwe");
124+
125+
JavaCalls.callMethod(xmPushService, "sendMessages", intent);
126+
127+
verify(eventListener).transferToServer(intent);
128+
}
129+
}
130+
131+
}

push/src/androidTest/java/test/com/xiaomi/push/service/service/MiPushMessageDuplicateAspectTest.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package test.com.xiaomi.push.service.service;
22

3+
import static com.xiaomi.push.service.PullAllApplicationDataFromServerJob.getPullAction;
34
import static org.junit.Assert.assertFalse;
45
import static org.junit.Assert.assertTrue;
56

67
import androidx.test.core.app.ApplicationProvider;
78

9+
import com.nihility.XMPushUtils;
810
import com.xiaomi.channel.commonutils.reflect.JavaCalls;
911
import com.xiaomi.push.service.MiPushMessageDuplicate;
1012
import com.xiaomi.push.service.MiPushMessageDuplicateAspect;
1113
import com.xiaomi.push.service.XMPushService;
14+
import com.xiaomi.xmpush.thrift.XmPushActionContainer;
15+
import com.xiaomi.xmpush.thrift.XmPushActionNotification;
1216

1317
import org.junit.Test;
1418

@@ -20,10 +24,13 @@ public class MiPushMessageDuplicateAspectTest {
2024

2125
@Test
2226
public void bypassMockedMiPushMessageDuplicationCheck() {
23-
String id = "message id";
27+
XmPushActionNotification pullAction = getPullAction("appId");
28+
XmPushActionContainer container = XMPushUtils.packToContainer(pullAction, "");
29+
30+
String id = pullAction.getId();
2431
ensureAlreadyDuplication(id);
2532

26-
MiPushMessageDuplicateAspect.mockId = "message id";
33+
MiPushMessageDuplicateAspect.markAsMock(container);
2734
assertFalse(checkDuplicationForId(id));
2835
}
2936

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package com.nihility;
2+
3+
import android.content.ContextWrapper;
4+
import android.content.Intent;
5+
6+
import androidx.annotation.Nullable;
7+
8+
import com.com.xiaomi.channel.commonutils.android.AppInfoUtilsAspect;
9+
import com.elvishew.xlog.Logger;
10+
import com.elvishew.xlog.XLog;
11+
import com.xiaomi.channel.commonutils.reflect.JavaCalls;
12+
import com.xiaomi.push.service.MIPushEventProcessorAspect;
13+
import com.xiaomi.push.service.PushConstants;
14+
import com.xiaomi.push.service.XMPushService;
15+
import com.xiaomi.xmpush.thrift.ActionType;
16+
import com.xiaomi.xmpush.thrift.PushMetaInfo;
17+
import com.xiaomi.xmpush.thrift.XmPushActionContainer;
18+
19+
import org.aspectj.lang.ProceedingJoinPoint;
20+
21+
public class MethodHooker {
22+
private static final String TAG = MethodHooker.class.getSimpleName();
23+
private static final Logger logger = XLog.tag(TAG).build();
24+
25+
private static class LazyHolder {
26+
static MethodHooker INSTANCE = new MethodHooker();
27+
}
28+
29+
private static MethodHooker instance;
30+
31+
public static MethodHooker instance() {
32+
return instance != null ? instance : LazyHolder.INSTANCE;
33+
}
34+
35+
public static void setInstance(MethodHooker methodHooker) {
36+
instance = methodHooker;
37+
}
38+
39+
public boolean shouldSendBroadcast(
40+
final ProceedingJoinPoint joinPoint,
41+
XMPushService pushService, String packageName, XmPushActionContainer container, PushMetaInfo metaInfo) throws Throwable {
42+
joinPoint.proceed();
43+
if (container.action == ActionType.Registration) {
44+
return true;
45+
}
46+
if (container.packageName.startsWith("com.mi.")
47+
|| container.packageName.startsWith("com.miui.")
48+
|| container.packageName.startsWith("com.xiaomi.")) {
49+
return true;
50+
}
51+
XmPushActionContainer decorated = MIPushEventProcessorAspect.decoratedContainer(container.packageName, container);
52+
return AppInfoUtilsAspect.shouldSendBroadcast(pushService, packageName, decorated.metaInfo);
53+
}
54+
55+
public volatile boolean isPostProcessMIPushMessage = false;
56+
public void postProcessMIPushMessage(
57+
final ProceedingJoinPoint joinPoint,
58+
XMPushService pushService, String pkgName, byte[] payload, Intent newMessageIntent) throws Throwable {
59+
isPostProcessMIPushMessage = true;
60+
61+
hookXMPushService(pushService);
62+
63+
try {
64+
joinPoint.proceed();
65+
} finally {
66+
isPostProcessMIPushMessage = false;
67+
}
68+
}
69+
70+
private volatile boolean XMPushServiceHooked = false;
71+
private void hookXMPushService(XMPushService pushService) {
72+
if (XMPushServiceHooked || pushService == null) {
73+
return;
74+
}
75+
synchronized (this) {
76+
if (XMPushServiceHooked) {
77+
return;
78+
}
79+
try {
80+
ContextWrapper wrapped = new ContextWrapper(pushService.getBaseContext()) {
81+
@Override
82+
public void sendBroadcast(Intent intent, @Nullable String receiverPermission) {
83+
if (isPostProcessMIPushMessage) {
84+
byte[] payload = intent.getByteArrayExtra(PushConstants.MIPUSH_EXTRA_PAYLOAD);
85+
MiPushEventListener.instance().transferToApplication(XMPushUtils.packToContainer(payload));
86+
}
87+
super.sendBroadcast(intent, receiverPermission);
88+
}
89+
};
90+
JavaCalls.setField(pushService, "mBase", wrapped);
91+
XMPushServiceHooked = true;
92+
} catch (Throwable e) {
93+
logger.e("hook xmpushservice failed", e);
94+
}
95+
}
96+
}
97+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.nihility;
2+
3+
import android.content.Intent;
4+
5+
import com.elvishew.xlog.Logger;
6+
import com.elvishew.xlog.XLog;
7+
import com.xiaomi.xmpush.thrift.XmPushActionContainer;
8+
import com.xiaomi.xmsf.utils.ConvertUtils;
9+
10+
public class MiPushEventListener {
11+
private static final String TAG = MiPushEventListener.class.getSimpleName();
12+
private static final Logger logger = XLog.tag(TAG).build();
13+
14+
private static class LazyHolder {
15+
volatile static MiPushEventListener INSTANCE = new MiPushEventListener();
16+
}
17+
18+
private static MiPushEventListener instance;
19+
20+
public static MiPushEventListener instance() {
21+
return instance != null ? instance : LazyHolder.INSTANCE;
22+
}
23+
24+
public static void setInstance(MiPushEventListener listener) {
25+
instance = listener;
26+
}
27+
28+
public void receiveFromServer(XmPushActionContainer container) {
29+
logger.i("From Server : " + ConvertUtils.toJson(container));
30+
}
31+
32+
public void transferToApplication(XmPushActionContainer container) {
33+
logger.i("To Application: " + ConvertUtils.toJson(container));
34+
}
35+
36+
public void receiveFromApplication(Intent intent) {
37+
logger.i("From Application: " + ConvertUtils.toJson(intent));
38+
}
39+
40+
public void transferToServer(Intent intent) {
41+
logger.i("To Server : " + ConvertUtils.toJson(intent));
42+
}
43+
44+
}

push/src/main/java/com/nihility/XMPushUtils.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,14 @@ public class XMPushUtils {
3737
}
3838

3939
public static @NonNull XmPushActionContainer packToContainer(XmPushActionNotification action, String packageName) {
40+
return packToContainer(action, packageName, ActionType.Notification, action.appId);
41+
}
42+
43+
public static @NonNull <T extends TBase<T, ?>> XmPushActionContainer packToContainer(T action, String packageName, ActionType actionType, String appId) {
4044
return JavaCalls.callStaticMethod(
4145
PushContainerHelper.class.getName(), "generateRequestContainer",
42-
Utils.getApplication(), action, ActionType.Notification,
43-
false, packageName, action.appId);
46+
Utils.getApplication(), action, actionType,
47+
false, packageName, appId);
4448
}
4549

4650
public static <T extends TBase<T, ?>> byte[] packToBytes(T container) {

push/src/main/java/com/xiaomi/push/service/LogXMPushServiceAspect.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import com.elvishew.xlog.Logger;
66
import com.elvishew.xlog.XLog;
7+
import com.nihility.MiPushEventListener;
78
import com.xiaomi.xmsf.utils.ConvertUtils;
89

910
import org.aspectj.lang.JoinPoint;
@@ -32,6 +33,7 @@ public void onStartCommand(final JoinPoint joinPoint) {
3233
public void onStart(final JoinPoint joinPoint, Intent intent, int startId) {
3334
logger.d(joinPoint.getSignature());
3435
logIntent(intent);
36+
MiPushEventListener.instance().receiveFromApplication(intent);
3537
}
3638

3739
@Before("execution(* com.xiaomi.push.service.XMPushService.onBind(..)) && args(intent)")
@@ -56,4 +58,9 @@ private void logIntent(Intent intent) {
5658
logger.d("Intent" + " " + ConvertUtils.toJson(intent));
5759
}
5860

61+
@Before("execution(* com.xiaomi.push.service.XMPushService.sendMessage*(..)) && args(intent)")
62+
public void sendMessage(final JoinPoint joinPoint, Intent intent) {
63+
logger.d(joinPoint.getSignature());
64+
MiPushEventListener.instance().transferToServer(intent);
65+
}
5966
}

0 commit comments

Comments
 (0)