From b2b2362f71f6b5df044e24e18c3c6eb14c0669cb Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Sat, 15 Sep 2018 21:19:15 +0800 Subject: [PATCH] fix(autojs): root automator not working on some device --- .../main/assets/modules/__RootAutomator__.js | 4 +- .../autojs/core/inputevent/InputDevices.java | 13 +- .../autojs/core/inputevent/RootAutomator.java | 137 ++++++++++++++---- .../com/stardust/autojs/core/util/Shell.java | 77 ++++++---- 4 files changed, 166 insertions(+), 65 deletions(-) diff --git a/autojs/src/main/assets/modules/__RootAutomator__.js b/autojs/src/main/assets/modules/__RootAutomator__.js index 8d909602..3d7073e5 100644 --- a/autojs/src/main/assets/modules/__RootAutomator__.js +++ b/autojs/src/main/assets/modules/__RootAutomator__.js @@ -1,6 +1,6 @@ module.exports = function(__runtime__, scope){ - function RootAutomator(){ - this.__ra__ = Object.create(new com.stardust.autojs.core.inputevent.RootAutomator(scope.context)); + function RootAutomator(nonBlockingForReady){ + this.__ra__ = Object.create(new com.stardust.autojs.core.inputevent.RootAutomator(scope.context, !nonBlockingForReady)); var methods = ["sendEvent", "touch", "setScreenMetrics", "touchX", "touchY", "sendSync", "sendMtSync", "tap", "swipe", "press", "longPress", "touchDown", "touchUp", "touchMove", "getDefaultId", "setDefaultId", "exit"]; for(var i = 0; i < methods.length; i++){ diff --git a/autojs/src/main/java/com/stardust/autojs/core/inputevent/InputDevices.java b/autojs/src/main/java/com/stardust/autojs/core/inputevent/InputDevices.java index be9572e0..fecef13f 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/inputevent/InputDevices.java +++ b/autojs/src/main/java/com/stardust/autojs/core/inputevent/InputDevices.java @@ -1,20 +1,31 @@ package com.stardust.autojs.core.inputevent; import android.support.annotation.Nullable; +import android.util.Log; import android.view.InputDevice; + /** * Created by Stardust on 2017/8/1. */ public class InputDevices { + private static final String LOG_TAG = "InputDevices"; + @Nullable public static String getTouchDeviceName() { + InputDevice device = getTouchDevice(); + return device == null ? null : device.getName(); + } + + @Nullable + public static InputDevice getTouchDevice() { for (int id : InputDevice.getDeviceIds()) { InputDevice device = InputDevice.getDevice(id); + Log.d(LOG_TAG, "device: " + device); if (supportSource(device, InputDevice.SOURCE_TOUCHSCREEN) || supportSource(device, InputDevice.SOURCE_TOUCHPAD)) { - return device.getName(); + return device; } } return null; diff --git a/autojs/src/main/java/com/stardust/autojs/core/inputevent/RootAutomator.java b/autojs/src/main/java/com/stardust/autojs/core/inputevent/RootAutomator.java index 852b811e..b63dd277 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/inputevent/RootAutomator.java +++ b/autojs/src/main/java/com/stardust/autojs/core/inputevent/RootAutomator.java @@ -1,37 +1,27 @@ package com.stardust.autojs.core.inputevent; import android.content.Context; -import android.os.Build; import android.os.SystemClock; import android.support.annotation.Nullable; +import android.util.Log; +import android.util.SparseIntArray; import android.view.ViewConfiguration; -import com.stardust.autojs.core.inputevent.InputDevices; -import com.stardust.autojs.core.util.ProcessShell; +import com.stardust.autojs.core.util.Shell; import com.stardust.autojs.engine.RootAutomatorEngine; -import com.stardust.autojs.runtime.api.AbstractShell; import com.stardust.autojs.runtime.exception.ScriptInterruptedException; import com.stardust.util.ScreenMetrics; import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; -import static com.stardust.autojs.core.inputevent.InputEventCodes.ABS_MT_POSITION_X; -import static com.stardust.autojs.core.inputevent.InputEventCodes.ABS_MT_POSITION_Y; -import static com.stardust.autojs.core.inputevent.InputEventCodes.ABS_MT_TOUCH_MAJOR; -import static com.stardust.autojs.core.inputevent.InputEventCodes.ABS_MT_TRACKING_ID; -import static com.stardust.autojs.core.inputevent.InputEventCodes.BTN_TOOL_FINGER; -import static com.stardust.autojs.core.inputevent.InputEventCodes.BTN_TOUCH; -import static com.stardust.autojs.core.inputevent.InputEventCodes.EV_ABS; -import static com.stardust.autojs.core.inputevent.InputEventCodes.EV_KEY; -import static com.stardust.autojs.core.inputevent.InputEventCodes.EV_SYN; -import static com.stardust.autojs.core.inputevent.InputEventCodes.SYN_MT_REPORT; -import static com.stardust.autojs.core.inputevent.InputEventCodes.SYN_REPORT; +import static com.stardust.autojs.core.inputevent.InputEventCodes.*; /** * Created by Stardust on 2017/7/16. */ -public class RootAutomator { +public class RootAutomator implements Shell.Callback { private static final String LOG_TAG = "RootAutomator"; @@ -43,22 +33,50 @@ public class RootAutomator { @Nullable private ScreenMetrics mScreenMetrics; - private AbstractShell mShell; - private int mDefaultId = 1; + private Shell mShell; + private int mDefaultId = 0; + private AtomicInteger mTracingId = new AtomicInteger(1); + private SparseIntArray mSlotIdMap = new SparseIntArray(); + private final Object mReadyLock = new Object(); + private volatile boolean mReady = false; + private final Context mContext; - public RootAutomator(Context context) { - mShell = new ProcessShell(true); - String path = RootAutomatorEngine.getExecutablePath(context); - String deviceNameOrPath = RootAutomatorEngine.getDeviceNameOrPath(context, InputDevices.getTouchDeviceName()); - mShell.exec("chmod 777 " + path); - mShell.exec(path + " -d " + deviceNameOrPath); + public RootAutomator(Context context, boolean waitForReady) throws IOException { + mContext = context; + mShell = new Shell(true); + mShell.setCallback(this); + if(waitForReady){ + waitForReady(); + } } public void sendEvent(int type, int code, int value) throws IOException { + waitForReady(); + sendEventInternal(type, code, value); + } + + private void sendEventInternal(int type, int code, int value) { mShell.exec(type + " " + code + " " + value); } + private void waitForReady() throws IOException { + if(mReady){ + return; + } + synchronized (mReadyLock){ + if(mReady){ + return; + } + try { + mReadyLock.wait(); + } catch (InterruptedException e) { + exit(); + throw new ScriptInterruptedException(); + } + } + } + public void touch(int x, int y) throws IOException { touchX(x); touchY(y); @@ -150,11 +168,28 @@ public class RootAutomator { } public void touchDown(int x, int y, int id) throws IOException { - sendEvent(EV_ABS, ABS_MT_TRACKING_ID, id); + if(mSlotIdMap.size() == 0){ + touchDown0(x, y, id); + return; + } + int slotId = mSlotIdMap.size(); + mSlotIdMap.put(id, slotId); + sendEvent(EV_ABS, ABS_MT_SLOT, slotId); + sendEvent(EV_ABS, ABS_MT_TRACKING_ID, mTracingId.getAndIncrement()); + sendEvent(EV_ABS, ABS_MT_POSITION_X, scaleX(x)); + sendEvent(EV_ABS, ABS_MT_POSITION_Y, scaleY(y)); + sendEvent(EV_ABS, ABS_MT_TOUCH_MAJOR, 5); + sendEvent(EV_SYN, SYN_REPORT, 0x00000000); + } + + private void touchDown0(int x, int y, int id) throws IOException { + mSlotIdMap.put(id, 0); + sendEvent(EV_ABS, ABS_MT_TRACKING_ID, mTracingId.getAndIncrement()); sendEvent(EV_KEY, BTN_TOUCH, 0x00000001); sendEvent(EV_KEY, BTN_TOOL_FINGER, 0x00000001); sendEvent(EV_ABS, ABS_MT_POSITION_X, scaleX(x)); sendEvent(EV_ABS, ABS_MT_POSITION_Y, scaleY(y)); + //sendEvent(EV_ABS, ABS_MT_PRESSURE, 200); sendEvent(EV_ABS, ABS_MT_TOUCH_MAJOR, 5); sendEvent(EV_SYN, SYN_REPORT, 0x00000000); } @@ -164,9 +199,20 @@ public class RootAutomator { } public void touchUp(int id) throws IOException { - sendEvent(EV_ABS, ABS_MT_TRACKING_ID, id); - sendEvent(EV_KEY, BTN_TOUCH, 0x00000000); - sendEvent(EV_KEY, BTN_TOOL_FINGER, 0x00000000); + int slotId ; + int i = mSlotIdMap.indexOfKey(id); + if( i < 0){ + slotId = 0; + }else { + slotId = mSlotIdMap.valueAt(i); + mSlotIdMap.removeAt(i); + } + sendEvent(EV_ABS, ABS_MT_SLOT, slotId); + sendEvent(EV_ABS, ABS_MT_TRACKING_ID, 0xffffffff); + if(mSlotIdMap.size() == 0){ + sendEvent(EV_KEY, BTN_TOUCH, 0x00000000); + sendEvent(EV_KEY, BTN_TOOL_FINGER, 0x00000000); + } sendEvent(EV_SYN, SYN_REPORT, 0x00000000); } @@ -175,7 +221,9 @@ public class RootAutomator { } public void touchMove(int x, int y, int id) throws IOException { - sendEvent(EV_ABS, ABS_MT_TRACKING_ID, id); + int slotId = mSlotIdMap.get(id, 0); + sendEvent(EV_ABS, ABS_MT_SLOT, slotId); + sendEvent(EV_ABS, ABS_MT_TOUCH_MAJOR, 5); sendEvent(EV_ABS, ABS_MT_POSITION_X, scaleX(x)); sendEvent(EV_ABS, ABS_MT_POSITION_Y, scaleY(y)); sendEvent(EV_SYN, SYN_REPORT, 0x00000000); @@ -207,7 +255,8 @@ public class RootAutomator { } public void exit() throws IOException { - sendEvent(0xffff, 0xffff, 0xefefefef); + sleep(1); + sendEventInternal(0xffff, 0xffff, 0xefefefef); mShell.exec("exit"); mShell.exec("exit"); mShell.exec("exit"); @@ -217,5 +266,33 @@ public class RootAutomator { mShell.exit(); } + @Override + public void onOutput(String str) { + + } + + @Override + public void onNewLine(String line) { + } + + @Override + public void onInitialized() { + String path = RootAutomatorEngine.getExecutablePath(mContext); + String deviceNameOrPath = RootAutomatorEngine.getDeviceNameOrPath(mContext, InputDevices.getTouchDeviceName()); + Log.d(LOG_TAG, "deviceNameOrPath: " + deviceNameOrPath); + mShell.exec("chmod 777 " + path); + String command = path + " -d " + deviceNameOrPath; + mShell.exec(command); + synchronized (mReadyLock){ + Log.d(LOG_TAG, "notify ready"); + mReady = true; + mReadyLock.notifyAll(); + } + } + + @Override + public void onInterrupted(InterruptedException e) { + + } } diff --git a/autojs/src/main/java/com/stardust/autojs/core/util/Shell.java b/autojs/src/main/java/com/stardust/autojs/core/util/Shell.java index 835ee518..406bf33f 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/util/Shell.java +++ b/autojs/src/main/java/com/stardust/autojs/core/util/Shell.java @@ -62,6 +62,7 @@ public class Shell extends AbstractShell { } } + private static final boolean DEBUG = true; private static final String TAG = "Shell"; private volatile TermSession mTermSession; @@ -97,16 +98,13 @@ public class Shell extends AbstractShell { @Override protected void init(final String initialCommand) { Handler uiHandler = new Handler(mContext.getMainLooper()); - uiHandler.post(new Runnable() { - @Override - public void run() { - TermSettings settings = new TermSettings(mContext.getResources(), PreferenceManager.getDefaultSharedPreferences(mContext)); - try { - mTermSession = new MyShellTermSession(settings, initialCommand); - mTermSession.initializeEmulator(1024, 40); - } catch (IOException e) { - mInitException = new UncheckedIOException(e); - } + uiHandler.post(() -> { + TermSettings settings = new TermSettings(mContext.getResources(), PreferenceManager.getDefaultSharedPreferences(mContext)); + try { + mTermSession = new MyShellTermSession(settings, initialCommand); + mTermSession.initializeEmulator(1024, 40); + } catch (IOException e) { + mInitException = new UncheckedIOException(e); } }); } @@ -126,12 +124,21 @@ public class Shell extends AbstractShell { private void ensureInitialized() { if (mTermSession == null) { + logDebug("ensureInitialized: not init"); checkInitException(); waitInitialization(); if (mTermSession == null) { checkInitException(); throw new IllegalStateException(); } + }else { + logDebug("ensureInitialized: init"); + } + } + + private void logDebug(String log){ + if(DEBUG){ + Log.d(TAG, log); } } @@ -142,11 +149,14 @@ public class Shell extends AbstractShell { } private void waitInitialization() { - if (mInitialized) - throw new IllegalStateException("already initialized"); synchronized (mInitLock) { + if(mInitialized){ + return; + } + logDebug("waitInitialization: enter"); try { mInitLock.wait(); + logDebug("waitInitialization: exit"); } catch (InterruptedException e) { onInterrupted(e); } @@ -209,33 +219,25 @@ public class Shell extends AbstractShell { } private void startReadingThread() { - mReadingThread = new ThreadCompat(new Runnable() { - @Override - public void run() { - String line; - try { - while (!Thread.currentThread().isInterrupted() - && (line = mBufferedReader.readLine()) != null) { - onNewLine(line); - } - } catch (IOException e) { - e.printStackTrace(); + mReadingThread = new ThreadCompat(() -> { + String line; + try { + while (!Thread.currentThread().isInterrupted() + && (line = mBufferedReader.readLine()) != null) { + onNewLine(line); } + } catch (IOException e) { + e.printStackTrace(); } }); mReadingThread.start(); } private void onNewLine(String line) { - //Log.d(TAG, line); + logDebug("onNewLine: " + line); if (!mInitialized) { - if (isRoot() && line.endsWith(" $ su")) { - notifyInitialized(); - return; - } if (!isRoot() && line.endsWith(" $ sh")) { notifyInitialized(); - return; } } if (mCallback != null) { @@ -246,13 +248,23 @@ public class Shell extends AbstractShell { } } + private void onOutput(String str){ + logDebug("onOutput: " + str); + if (!mInitialized) { + if (isRoot() && str.endsWith(":/ # ")) { + notifyInitialized(); + } + } + if (mCallback != null) { + mCallback.onOutput(str); + } + } + @Override protected void processInput(byte[] data, int offset, int count) { try { - if (mCallback != null) { - mCallback.onOutput(new String(data, offset, count)); - } + onOutput(new String(data, offset, count)); mOutputStream.write(data, offset, count); } catch (IOException e) { e.printStackTrace(); @@ -268,6 +280,7 @@ public class Shell extends AbstractShell { } private void notifyInitialized() { + logDebug("notifyInitialized"); mInitialized = true; synchronized (mInitLock) { mInitLock.notifyAll();