Closed ryuunoakaihitomi closed 4 years ago
@GrenderG There are 2 unrelated bugs in Toast, but their solutions must be combined in order to fix it non-invasively. I am not quite proficient with naming, so I have no idea for more descriptive name. You can merge this PR and rename it later.
In short, these solutions use dynamic proxy to fix.
Toast
public void show() {
if (mNextView == null) {
throw new RuntimeException("setView must have been called");
}
// ATTENTION:
// NotificationManagerService, AIDL: INotificationManager
// We can use dynamic proxy here.
INotificationManager service = getService();
// ATTENTION: Parameter[0]: package name.
String pkg = mContext.getOpPackageName();
// ATTENTION: Parameter[1]: TransientNotification. Can be used to fix BadTokenException
TN tn = mTN;
tn.mNextView = mNextView;
final int displayId = mContext.getDisplayId();
try {
// ATTENTION: Go to NotificationManagerService.enqueue(...)
service.enqueueToast(pkg, tn, mDuration, displayId);
} catch (RemoteException e) {
// Empty
}
}
NotificationManagerService
@Override
public void enqueueToast(String pkg, ITransientNotification callback, int duration)
{
if (DBG) {
Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
+ " duration=" + duration);
}
if (pkg == null || callback == null) {
Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
return ;
}
// ATTENTION: System Toast: "android".equals(pkg)
final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
final boolean isPackageSuspended =
isPackageSuspendedForUser(pkg, Binder.getCallingUid());
// ATTENTION: Check notification permission.
if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
(!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
|| isPackageSuspended)) {
Slog.e(TAG, "Suppressing toast from package " + pkg
+ (isPackageSuspended
? " due to package suspended by administrator."
: " by user request."));
return;
}
...
Here‘s a solution that describes the cause of the bug in detail. ToastCompat But it's invasive, we have to replace all existing Toasts to fix the bug. Inspired by this article, I change the hook point and use dynamic proxy in order to make less invasive.
private static class TN extends ITransientNotification.Stub {
...
final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
IBinder token = (IBinder) msg.obj;
// ATTENTION: BTE!
handleShow(token);
}
};
Why not merge my pr or just give me a response? Did I do something wrong?
Haven't had time yet to review your code, sorry!
It's OK. I don't think it will take long to review this code, but I'm still pleased to receive your reply.
Can you please explain what the code you added is doing? (Also, maybe use a more descriptive name for the method).
Thanks.