Generating keypresses programmatically

 

Generating keypresses programmatically

There was already a blog entry about programmatically generating key events but I was not satisfied with the outcome. The Instrumentation framework is nice but is somewhat heavyweight. If one wants to generate just keypresses, why to have all those entries in the manifest, instrumentation object, etc? So I used the wonderful new dedexer tool to go after the inner workings of the instrumentation framework.

The critical method in android.app.Instrumentation is this:

.method public sendKeySync(Landroid/view/KeyEvent;)V
.catch android/os/RemoteException from le5cf6 to le5d12 using le5d14
 invoke-direct    {v2},android/app/Instrumentation/validateNotAppThread
                 ; validateNotAppThread()V
le5cf6:
 const-string    v0,"window"
 invoke-static    {v0},android/os/ServiceManager/getService
                 ; getService(Ljava/lang/String;)Landroid/os/IBinder;
 move-result-object    v0
 invoke-static    {v0},android/view/IWindowManager$Stub/asInterface    
                 ; asInterface(Landroid/os/IBinder;)Landroid/view/IWindowManager;
 move-result-object    v0
 const/4    v1,1
 invoke-interface    {v0,v3,v1},android/view/IWindowManager/injectKeyEvent    
                 ; injectKeyEvent(Landroid/view/KeyEvent;Z)Z
le5d12:
 return-void
le5d14:
 move-exception    v0
 goto    le5d12
.end method


This is actually a public API method. The method obtains the binder of the WindowManagerService from the ServiceManager then it invokes the injectKeyEvent method on WindowManagerService's public interface. That is something we can do ourselves, can't we?

Click here to download the example program.

Unfortunately the situation is not that simple. Ever since the non-public classes like android.os.ServiceManager, android.view.IWindowManager, etc. were removed from android.jar, applications using non-public API cannot be compiled as easily as before. If you check the example program, you will see that I created stubs for these classes. These stubs are only there to allow compilation of the program, they don't get packaged into the apk file. On the platform itself, there will be real versions of them. In order to accomodate the stub compilation step, I modified somewhat the machine-generated build.xml file too.

It is also important to notice the validateNotAppThread private method invocation at the beginning of the method. Events cannot be generated neither from the application's own thread, nor from the UI thread. That's the reason we prepare another thread and install a looper into it. Then we post our actions into that thread and that thread will be able to generate keypresses.


If you launch the program and press the "Generate keypresses" button, you will see how the text field above the button receives the keypresses we generated programmatically. At this point you may get excited and would try to generate keypresses for other applications. This will not work. Android applications are allowed to generate keypresses only for themselves. In WindowManagerService class, you will find a permission check controlling this behaviour.

 iget-object    v1,v12,com/android/server/WindowManagerService.mContext Landroid/content/Context;
 const-string    v2,"android.permission.INJECT_EVENTS"
 invoke-virtual    {v1,v2,v14,v15},android/content/Context/checkPermission    
                     ; checkPermission(Ljava/lang/String;II)I
 move-result    v1
 if-eqz    v1,l4a7e0
 const-string    v1,"WindowManager"
 new-instance    v1,java/lang/StringBuilder
 invoke-direct    {v1},java/lang/StringBuilder/    
                     ; ()V
 const-string    v2,"Permission denied: injecting key event from pid "


The android.permission.INJECT_EVENT permission is not that of the application, the WindowManagerService must have this permission otherwise requests to inject events into other applications' windows will be rejected. By default, WindowManagerService does not have this permission, that is why it is impossible to generate events for somebody else's window.

After all this diving into Android's internals, I show that there is a simpler way to generate key events by abusing the android.app.Instrumentation class. Check out the generateKeysWInst method in the example program. This method simply instantiates the Instrumentation class and calls only the sendKeyDownUpSync public method. This works because we know that sendKeyDownUpSync is so simple that it will function even with this bizarrely created instrumentation object. I don't know which method is more futureproof: using internal, non-public API or abusing a public API. Decide yourself.
 
http://mylifewithandroid.blogspot.com/2009/01/generating-keypresses-programmatically.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值