Skip to content

Instantly share code, notes, and snippets.

@RikkaW
Last active October 2, 2024 14:10
Show Gist options
  • Save RikkaW/be3fe4178903702c54ec73b2fc1187fe to your computer and use it in GitHub Desktop.
Save RikkaW/be3fe4178903702c54ec73b2fc1187fe to your computer and use it in GitHub Desktop.
show window in app_process (impossible to work from Android 14 QPR 3 or Android 15, as addView requires the calling process an Android app process)
token = new Binder();
try {
Context _context = android.app.ActivityThread.systemMain().getSystemContext();
final Context context = new ContextWrapper(_context) {
@Override
public Object getSystemService(String name) {
if (Context.WINDOW_SERVICE.equals(name)) {
WindowManager wm = (WindowManager) super.getSystemService(name);
if (wm != null) {
((android.view.WindowManagerImpl) wm).setDefaultToken(token);
}
return wm;
}
return super.getSystemService(name);
}
};
context.setTheme(android.R.style.Theme_Material_Light);
CharSequence label = context.getPackageManager().getApplicationLabel(context.getPackageManager().getApplicationInfo("com.android.settings", 0));
LogUtils.i("label " + label);
android.widget.Toast.makeText(context, "test", Toast.LENGTH_LONG).show();
LogUtils.i("toast");
android.view.WindowManager wm = context.getSystemService(WindowManager.class);
LogUtils.i("class: " + wm.getClass().getName());
//((android.view.WindowManagerImpl) wm).setDefaultToken(token);
LinearLayout root = new LinearLayout(context);
root.setBackground(new ColorDrawable(0xffffffff));
TextView textView = new TextView(context);
textView.setText("test");
root.addView(textView);
Button button = new Button(context);
button.setSoundEffectsEnabled(false);
button.setText("test");
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, "?!", Toast.LENGTH_LONG).show();
}
});
root.addView(button);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.CENTER;
params.x = 0;
params.y = 0;
wm.addView(root, params);
} catch (Throwable tr) {
LogUtils.e(tr.getMessage(), tr);
}
@huynhtanloc2612
Copy link

Thanks @JacobTDC for your comment
I've tried your suggestion

public class ShowToast {
    public static void main(String[] args) {
        Binder token = new Binder();
        Looper.prepareMainLooper();
        try{
            Context _context = ActivityThread.systemMain().getSystemContext();
            Context context = new ContextWrapper(_context) {
                @Override
                public String getOpPackageName() {
                  return "com.android.shell"; // aka ADB shell package name
                }
            };
            Toast.makeText(context, "test", Toast.LENGTH_LONG).show();
        } catch (Throwable tr) {
            tr.printStackTrace(System.err);
        }
    }
}

but I still got the below error on Galaxy phone with Android 14

$ adb shell app_process -cp /data/local/tmp/toast.dex / com.htl.toast14.ShowToast

java.lang.SecurityException: Given calling package android does not match caller's uid 2000
	at android.os.Parcel.createExceptionOrNull(Parcel.java:3069)
	at android.os.Parcel.createException(Parcel.java:3053)
	at android.os.Parcel.readException(Parcel.java:3036)
	at android.os.Parcel.readException(Parcel.java:2978)
	at android.app.IActivityManager$Stub$Proxy.getContentProvider(IActivityManager.java:6393)
	at android.app.ActivityThread.acquireProvider(ActivityThread.java:8160)
	at android.app.ContextImpl$ApplicationContentResolver.acquireProvider(ContextImpl.java:3838)
	at android.content.ContentResolver.acquireProvider(ContentResolver.java:2539)
	at android.provider.Settings$ContentProviderHolder.getProvider(Settings.java:3328)
	at android.provider.Settings$NameValueCache.getStringForUser(Settings.java:3595)
	at android.provider.Settings$System.getStringForUser(Settings.java:4362)
	at android.provider.Settings$System.getIntForUser(Settings.java:4493)
	at android.provider.Settings$System.getInt(Settings.java:4465)
	at android.widget.Toast.checkGameHomeAllowList(Toast.java:1108)
	at android.widget.Toast.show(Toast.java:313)
	at com.htl.toast14.ShowToast.main(ShowToast.java:28)
	at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
	at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:395)
Caused by: android.os.RemoteException: Remote stack trace:
	at com.android.server.am.ContentProviderHelper.getContentProvider(ContentProviderHelper.java:148)
	at com.android.server.am.ActivityManagerService.getContentProvider(ActivityManagerService.java:8700)
	at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:3091)
	at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3202)
	at android.os.Binder.execTransactInternal(Binder.java:1375)

Do you have any idea?
And can you show your full code?
Thanks.

@JacobTDC
Copy link

JacobTDC commented Oct 1, 2024

@huynhtanloc2612, the following works for me, I tested it in ADB as well.

$ adb shell app_process -cp /data/local/tmp/toast.dex /system/bin/ { class/package path }.ShowToast
public class ShowToast {
  public static final void main(String[] args) {
    Looper.prepare();

    ActivityThread activityThread = ActivityThread.systemMain();

    Context _context = activityThread.getSystemContext();
    Context context = new ContextWrapper(_context) {
      @Override
      public String getOpPackageName() {
        return "com.android.shell";
      }
    };

    // Maybe create a `new Handler(Looper.myLooper())` and wrap this
    // in `handler.post(() -> { ... }); Looper.loop();` if it doesn't work?
    // If you do, don't forget to add `Looper.myLooper().quit[Safely]()`
    // inside the `handler.post(() -> { ... });`.
    Toast.makeText(context, "test", Toast.LENGTH_LONG).show();
  }
}

If that doesn't work, maybe try something like this for creating and wrapping the context:

  static Context createPackageContext(String packageName) {
    Context sysCtx = ActivityThread.systemMain().getSystemContext();

    Context _context;
    try {
      _context = (Context) Context.class
        .getMethod("createPackageContextAsUser", new Class[] {
          String.class,
          int.class,
          UserHandle.class })
        .invoke(sysCtx, packageName, 0, Process.myUserHandle());
    } catch (Exception exc) {
      throw new RuntimeException(exc);
    }

    return new ContextWrapper(_context) {
      @Override
      public String getOpPackageName() {
        return packageName;
      }
    };
  }

What device are you using? I see you're using a Galaxy. That could make a difference, but I'm not sure. I'm using a Google Pixel 8 Pro.

@huynhtanloc2612
Copy link

Thanks @JacobTDC ,
Try your above suggestions but the same error happens when it executes Toast.makeText(...).show()
java.lang.SecurityException: Given calling package android does not match caller's uid 2000

I think it requires Android app process as the note of @RikkaW "addView requires the calling process an Android app process"

@D-R-99
Copy link

D-R-99 commented Oct 2, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment