Genymobile / scrcpy

Display and control your Android device
Apache License 2.0
111.82k stars 10.7k forks source link

FakeContext class is not working with Java application #4165

Open huynhtanloc2612 opened 1 year ago

huynhtanloc2612 commented 1 year ago

Hi @rom1v @yume-chan , Thank for making the fake context class (FakeContext.java) I am trying to use it to create the fake context for testing a java application with adb command (app_process). My java application of HelloWorld.java is shown below

import android.os.SystemClock;
import android.widget.Toast;
public class HelloWorld {
     public static void main(String... args) {
         System.out.print("Hello,");
         SystemClock.sleep(1000);
         System.out.println(" world!!!");
         Toast.makeText(FakeContext.get(),"Hello World!!!",Toast.LENGTH_LONG).show();
     }
}

After successfully compiled, dex-ed and push it to android device, I tried to run it with below command adb shell CLASSPATH=/data/local/tmp/classes.dex app_process / HelloWorld

The result showed in terminal is below

Hello, world!!!
Killed

And no toast message was showed on android device (Android 12) -> The fake context did not work in this case Do you have any idea or suggestion? Thanks,

rom1v commented 1 year ago

The FakeContext only provides some methods necessary for scrcpy, it is not a real Android context.

Maybe you can do more things with a parent system context: https://github.com/Genymobile/scrcpy/commit/ce8d3ac6d145724949060c8bbe139a204d901adf (it's not used in scrcpy because it causes issues on some devices).

But like many things exposed in Context, to show a toast, I think you'd have to call the underlying API at a lower level (via AIDL or something).

huynhtanloc2612 commented 1 year ago

Thanks @rom1v for your suggestions. Maybe you can do more things with a parent system context: https://github.com/Genymobile/scrcpy/commit/ce8d3ac6d145724949060c8bbe139a204d901adf (it's not used in scrcpy because it causes issues on some devices). I've tried this but it still cannot work (it showed "Killed" and no toast appeared)

But like many things exposed in Context, to show a toast, I think you'd have to call the underlying API at a lower level (via AIDL or something). Could you give me some guideline or examples for this? (BTW, I have been following some of your great guidelines/examples so far to reach this step :) )

rom1v commented 1 year ago

For example, instead of calling Context.startActivity(Intent) (which internally calls a method on a system process via aidl), call the aidl function startActivityAsUserWithFeature().

In scrcpy, the call is done here. More generally, this is what wrappers mostly do.

huynhtanloc2612 commented 1 year ago

Thanks @rom1v, it is really impressive. I have been finding the correlation between Context.startActivity(Intent) and startActivityAsUserWithFeature() by checking the codes. But it is quite difficult to see the correlation. Is there any way to help to see their correlation so that I can try to do the same as what you did for other methods/functions? (if not, it is no problem :) )

rom1v commented 1 year ago

Basically you should search for "services" in AIDL in frameworks_base in AOSP, for example IActivityManager.aidl, IClipboard.aidl, IPowerManager.aidl...

huynhtanloc2612 commented 1 year ago

Basically you should search for "services" in AIDL in frameworks_base in AOSP, for example IActivityManager.aidl, IClipboard.aidl, IPowerManager.aidl...

Thanks @rom1v . However, I cannot find out any "services" keyword in IActivityManager.aidl, IClipboard.aidl, IPowerManager.aidl...

rom1v commented 1 year ago

Sorry, what I meant was using service names (that can be passed to Context.getSystemService()) to find aidl files in frameworks_base in AOSP (their name is based on the service names).

Then read the files to see what is exposed.

huynhtanloc2612 commented 1 year ago

Sorry, what I meant was using service names (that can be passed to Context.getSystemService()) to find aidl files in frameworks_base in AOSP (their name is based on the service names).

Then read the files to see what is exposed.

In case of Toast , I see two service names of WINDOW_SERVICE and LAYOUT_INFLATER_SERVICE. I think IWindowManager.aidl is the only one I should make a wrapper, right? (Cannot see any aidl file for LAYOUT_INFLATER_SERVICE). Can you tell how can I make a wrapper for IWindowManager.aidl? (My purpose is now to make the Toast.makeText(Context, String, Duation).show() work with app_process Thanks.

dyno314 commented 1 year ago

@huynhtanloc2612

https://gist.github.com/RikkaW/be3fe4178903702c54ec73b2fc1187fe

Maybe from here u get some idea. First try in Android 10-11, because its easy in those versions I have one app that using app_process, i injected code for Toast and it worked, unfortunately app is highly Obfuscated