问题是这样:
我现在有一个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的)。
不知道作者有什么好的解决方案。