Open wywlds opened 8 years ago
问题是这样: 我现在有一个Service,为了保持长连,使用Alarm Manager:
PendingIntent pi = PendingIntent.getService(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT); alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + KEEP_ALIVE_INTERVAL, KEEP_ALIVE_INTERVAL, pi);
在PendingIntent.getService方法里面会调用到
IIntentSender target = ActivityManagerNative.getDefault().getIntentSender( ActivityManager.INTENT_SENDER_SERVICE, packageName, null, null, requestCode, new Intent[] { intent }, resolvedType != null ? new String[] { resolvedType } : null, flags, null, UserHandle.myUserId());
这个方法已经被hook了,我们会把它做替换,在IActivityManagerHookHandle.java:
//这里我们用新的逻辑,将原来的PendingIntent.getXXX(XXX,XXX, Intent, XXX)全部替换成 //PendingIntent.getService(XXX,XXX,intetn,XXX) //这样系统在处理的时候,会先调用到我们的中转服务,我们的中转服务再来处理这个事情。 Intent replaced = replace(type, intent);
private Intent replace(int type, Intent intent) throws RemoteException { if (type == ActivityManagerCompat.INTENT_SENDER_SERVICE) { ServiceInfo a = resolveService(intent); if (a != null && isPackagePlugin(a.packageName)) { Intent newIntent = new Intent(mHostContext, PluginManagerService.class); newIntent.putExtra(Env.EXTRA_TARGET_INTENT, intent); newIntent.putExtra(Env.EXTRA_TYPE, type); newIntent.putExtra(Env.EXTRA_ACTION, "PendingIntent"); return newIntent; } } else if (type == ActivityManagerCompat.INTENT_SENDER_ACTIVITY) { ActivityInfo a = resolveActivity(intent); if (a != null && isPackagePlugin(a.packageName)) { Intent newIntent = new Intent(mHostContext, PluginManagerService.class); newIntent.putExtra(Env.EXTRA_TARGET_INTENT, intent); Log.e("wywdbg", "replace intent: %s", intent); newIntent.putExtra(Env.EXTRA_TYPE, type); newIntent.putExtra(Env.EXTRA_ACTION, "PendingIntent"); return newIntent; } } return null; }
但是在系统的getIntentSender方法中会复用原有的PendingIntent,然后将信息替换成新的,源代码如下:
PendingIntentRecord.Key key = new PendingIntentRecord.Key( type, packageName, activity, resultWho, requestCode, intents, resolvedTypes, flags, options, userId); WeakReference<PendingIntentRecord> ref; ref = mIntentSenderRecords.get(key); PendingIntentRecord rec = ref != null ? ref.get() : null; if (rec != null) { if (!cancelCurrent) { if (updateCurrent) { if (rec.key.requestIntent != null) { rec.key.requestIntent.replaceExtras(intents != null ? intents[intents.length - 1] : null); } if (intents != null) { intents[intents.length-1] = rec.key.requestIntent; rec.key.allIntents = intents; rec.key.allResolvedTypes = resolvedTypes; } else { rec.key.allIntents = null; rec.key.allResolvedTypes = null; } } return rec; } rec.canceled = true; mIntentSenderRecords.remove(key); } if (noCreate) { return rec; } rec = new PendingIntentRecord(this, key, callingUid); mIntentSenderRecords.put(key, rec.ref); if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { if (activity.pendingResults == null) { activity.pendingResults = new HashSet<WeakReference<PendingIntentRecord>>(); } activity.pendingResults.add(rec.ref); } return rec;
由于我们统一换成了先从PluginManagerService中转,这样就会出现已经注册在AlarmManager里面的PendingIntent在这种时候被修改了,导致打开的不是我们想注册打开的service而是后面调用到PendingIntent.getService的其他组件,比如说一个通知栏注册点击事件时的PendingIntent(这种通常是会打开Activity的)。
不知道作者有什么好的解决方案。
现在倒是有一个办法绕过,app里面每个使用到PendingIntent的地方采用同一套requestCode排重方式。
或者针对不同的Service和Activity使用不同的requestCode的base,这个可以通过修改DroidPlugin来实现。
问题是这样: 我现在有一个Service,为了保持长连,使用Alarm Manager:
在PendingIntent.getService方法里面会调用到
这个方法已经被hook了,我们会把它做替换,在IActivityManagerHookHandle.java:
但是在系统的getIntentSender方法中会复用原有的PendingIntent,然后将信息替换成新的,源代码如下:
由于我们统一换成了先从PluginManagerService中转,这样就会出现已经注册在AlarmManager里面的PendingIntent在这种时候被修改了,导致打开的不是我们想注册打开的service而是后面调用到PendingIntent.getService的其他组件,比如说一个通知栏注册点击事件时的PendingIntent(这种通常是会打开Activity的)。
不知道作者有什么好的解决方案。