Monkey source code analysis: Event source code

Source: Internet
Author: User

Monkey source code analysis: Event source code


The previous article "running process of Monkey source code analysis" provided the whole process of running monkey, which gave us an overview. In the future, we will try to explain some related knowledge points.

Here we will first give the structure of the entire monkey class for your reference. This figure is sourced from the Internet (my own backbook pro does not have the OmniGraffle tool installed, for $55, not willing, so directly paste it online)



Note the following points in the figure:

  • MonkeyEventScript should be MonkeySourceScript
  • MonkeyEventRandom should be MonkeySourceRandom
  • Other sources are not listed here. For example, the key MonkeySourceNetwork we described today is not maintained by the MonkeyEventQueque class. However, the event queue maintained by MonkeyEventQueque inherits from the queue list like MonkeyEventQueque, so similar

The focus of this article is to illustrate how the event source is handled by taking the sokcet, or monkeyrunner command from the network as an example. Other sources are similar.

1. event queue maintainer CommandQueque

Before getting started, we need to first learn about several basic classes so that we can easily analyze them.

After obtaining the event source, we will queue these events into a queue, and then we can retrieve the events in the queue for further processing elsewhere. Here we will first look at the corresponding code for maintaining this event queue:

    public static interface CommandQueue {        /**         * Enqueue an event to be returned later.  This allows a         * command to return multiple events.  Commands using the         * command queue still have to return a valid event from their         * translateCommand method.  The returned command will be         * executed before anything put into the queue.         *         * @param e the event to be enqueued.         */        public void enqueueEvent(MonkeyEvent e);    };    // Queue of Events to be processed.  This allows commands to push    // multiple events into the queue to be processed.    private static class CommandQueueImpl implements CommandQueue{        private final Queue<MonkeyEvent> queuedEvents = new LinkedList<MonkeyEvent>();        public void enqueueEvent(MonkeyEvent e) {            queuedEvents.offer(e);        }        /**         * Get the next queued event to excecute.         *         * @return the next event, or null if there aren't any more.         */        public MonkeyEvent getNextQueuedEvent() {            return queuedEvents.poll();        }    };

The CommandQueue interface defines only one method enqueueEvent, which is implemented by the Implementation class CommandQueueImpl. The implementation class maintains a queue quequeEvents of the MonkeyEvent type implemented by the queue list, then, two methods are implemented to place and retrieve events in the queue respectively. It is quite simple to implement. Here we mainly want to remind you of the importance of the queue queueEvents. Here, we should note that the classes of the MonkeyEventScript and monkeyEventRandom event sources for maintaining queues are slightly different. They use the MonkeyEventQueue class, but in fact this class also inherits from the sequence list described above, so the principle is the same.

Create and maintain an instance commandQueque of the CommandQueueImple implementation class to manage the quequeEvents.

    private final CommandQueueImpl commandQueue = new CommandQueueImpl();


2. Event interpreter MonkeyCommand

The next basic internal class we need to know is MonkeCommand. The commands from the data source are all strings. We need to convert them into corresponding monkey events and add them to the event queue quequeEvents maintained by CommandQueque mentioned above. First, let's take a look at the MonkeyCommand interface:

    /**     * Interface that MonkeyCommands must implement.     */    public interface MonkeyCommand {        /**         * Translate the command line into a sequence of MonkeyEvents.         *         * @param command the command line.         * @param queue the command queue.         * @return MonkeyCommandReturn indicating what happened.         */        MonkeyCommandReturn translateCommand(List<String> command, CommandQueue queue);    }

It only defines the method translateCommand to be implemented by an implementation class, which can be known from its description and accepted parameters, the task of this method is to convert the string commands received from the event source to the eventQueues maintained by the CommandQueue type mentioned above. Take the press Command sent by monkeyrunner as an example. The string passed to monkey is "press KEY_COKDE". (For details, refer to MonkeyRunner source code analysis and Android communication method.)

For each command, there will be a corresponding MonkeyCommand implementation class for real string-to-event translation. Taking the press command just mentioned as an example, let's take a look at its implementation code:

    /**     * Command to "press" a buttons (Sends an up and down key event.)     */    private static class PressCommand implements MonkeyCommand {        // press keycode        public MonkeyCommandReturn translateCommand(List<String> command,                                                    CommandQueue queue) {            if (command.size() == 2) {                int keyCode = getKeyCode(command.get(1));                if (keyCode < 0) {                    // Ok, you gave us something bad.                    Log.e(TAG, "Can't find keyname: " + command.get(1));                    return EARG;                }                queue.enqueueEvent(new MonkeyKeyEvent(KeyEvent.ACTION_DOWN, keyCode));                queue.enqueueEvent(new MonkeyKeyEvent(KeyEvent.ACTION_UP, keyCode));                return OK;            }            return EARG;        }    }
Take the 'Press KEY_CODE 'from monkeyrunner as an example to analyze this Code:

  • Obtain the 1st parameter from the string, that is, key_code.
  • Judge if key_code is valid
  • Create the MonkeyKeyEvent event that is pressed and enter the quequeEvents maintained by CommandQueque.
  • Create a MonkeyKeyEvent event with the pop-up key and add it to the quequeEvents maintained by CommandQueque (press this action to start and press the start button)
The correspondence between the command string and the corresponding MonkeyCommand implementation class will be maintained by the COMMAND_MAP private static member of the MonkeySourceNetwork class. Here we only analyze the "press" command, if you are interested, you can analyze it on your own. The principle is the same.

private static final Map<String, MonkeyCommand> COMMAND_MAP = new HashMap<String, MonkeyCommand>();    static {        // Add in all the commands we support        COMMAND_MAP.put("flip", new FlipCommand());        COMMAND_MAP.put("touch", new TouchCommand());        COMMAND_MAP.put("trackball", new TrackballCommand());        COMMAND_MAP.put("key", new KeyCommand());        COMMAND_MAP.put("sleep", new SleepCommand());        COMMAND_MAP.put("wake", new WakeCommand());        COMMAND_MAP.put("tap", new TapCommand());        COMMAND_MAP.put("press", new PressCommand());        COMMAND_MAP.put("type", new TypeCommand());        COMMAND_MAP.put("listvar", new MonkeySourceNetworkVars.ListVarCommand());        COMMAND_MAP.put("getvar", new MonkeySourceNetworkVars.GetVarCommand());        COMMAND_MAP.put("listviews", new MonkeySourceNetworkViews.ListViewsCommand());        COMMAND_MAP.put("queryview", new MonkeySourceNetworkViews.QueryViewCommand());        COMMAND_MAP.put("getrootview", new MonkeySourceNetworkViews.GetRootViewCommand());        COMMAND_MAP.put("getviewswithtext",                        new MonkeySourceNetworkViews.GetViewsWithTextCommand());        COMMAND_MAP.put("deferreturn", new DeferReturnCommand());    }

3. getNextEvent of the event Source

Finally, how to obtain the event analysis is reached. We continue to use the MonkeySourceNetwork network command to process monkeyrunner as an example to see how it handles the commands from monkeyrunner. Let's take a look at the implementation of the Interface Class MonkeyEventSource.

/** * event source interface */public interface MonkeyEventSource {    /**     * @return the next monkey event from the source     */    public MonkeyEvent getNextEvent();    /**     * set verbose to allow different level of log     *     * @param verbose output mode? 1= verbose, 2=very verbose     */    public void setVerbose(int verbose);    /**     * check whether precondition is satisfied     *     * @return false if something fails, e.g. factor failure in random source or     *         file can not open from script source etc     */    public boolean validate();}

Here, I am most concerned about the getNextEvent interface, because it is used to obtain the monkeyrunner command from the socket, then, the implementation class of the MonkeyCommand described above is used to translate the command into the quequeEvents queue maintained by the top CommandQueque. Next we will see how it works. Here we will first look at the constructor of the interface implementation class MonkeySourceNetwork:

    public MonkeySourceNetwork(int port) throws IOException {        // Only bind this to local host.  This means that you can only        // talk to the monkey locally, or though adb port forwarding.        serverSocket = new ServerSocket(port,                                        0, // default backlog                                        InetAddress.getLocalHost());    }
All you need to do is instantiate a ServerSocket through the specified port. Note that it is only bound to the local host address, this means that only the local socket connection or the adb port connected through port forwarding (that is, the adb started by monkeyrunner in this article) will be accepted.

A socket is instantiated here. So far, it has not been started, that is, it has not started to really start listening to the specified port. The actual start listening is triggered by startServer:

    /**     * Start a network server listening on the specified port.  The     * network protocol is a line oriented protocol, where each line     * is a different command that can be run.     *     * @param port the port to listen on     */    private void startServer() throws IOException {        clientSocket = serverSocket.accept();        // At this point, we have a client connected.        // Attach the accessibility listeners so that we can start receiving        // view events. Do this before wake so we can catch the wake event        // if possible.        MonkeySourceNetworkViews.setup();        // Wake the device up in preparation for doing some commands.        wake();        input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));        // auto-flush        output = new PrintWriter(clientSocket.getOutputStream(), true);    }
In addition to listening for ports, monkeyrunner maintains and instantiates the input and output member variables to operate port data.
Who calls this startServer method to start listening to data? This chapter is the core of this article, getNextEvent.
    public MonkeyEvent getNextEvent() {        if (!started) {            try {                startServer();            } catch (IOException e) {                Log.e(TAG, "Got IOException from server", e);                return null;            }            started = true;        }        // Now, get the next command.  This call may block, but that's OK        try {            while (true) {                // Check to see if we have any events queued up.  If                // we do, use those until we have no more.  Then get                // more input from the user.                MonkeyEvent queuedEvent = commandQueue.getNextQueuedEvent();                if (queuedEvent != null) {                    // dispatch the event                    return queuedEvent;                }                // Check to see if we have any returns that have been deferred. If so, now that                // we've run the queued commands, wait for the given event to happen (or the timeout                // to be reached), and handle the deferred MonkeyCommandReturn.                if (deferredReturn != null) {                    Log.d(TAG, "Waiting for event");                    MonkeyCommandReturn ret = deferredReturn.waitForEvent();                    deferredReturn = null;                    handleReturn(ret);                }                String command = input.readLine();                if (command == null) {                    Log.d(TAG, "Connection dropped.");                    // Treat this exactly the same as if the user had                    // ended the session cleanly with a done commant.                    command = DONE;                }                if (DONE.equals(command)) {                    // stop the server so it can accept new connections                    try {                        stopServer();                    } catch (IOException e) {                        Log.e(TAG, "Got IOException shutting down!", e);                        return null;                    }                    // return a noop event so we keep executing the main                    // loop                    return new MonkeyNoopEvent();                }                // Do quit checking here                if (QUIT.equals(command)) {                    // then we're done                    Log.d(TAG, "Quit requested");                    // let the host know the command ran OK                    returnOk();                    return null;                }                // Do comment checking here.  Comments aren't a                // command, so we don't echo anything back to the                // user.                if (command.startsWith("#")) {                    // keep going                    continue;                }                // Translate the command line.  This will handle returning error/ok to the user                translateCommand(command);            }        } catch (IOException e) {            Log.e(TAG, "Exception: ", e);            return null;        }    }
With the background knowledge introduced above, the understanding of this code will not be too laborious. I will describe it here:

  • Start the socket port to listen for connections and data from monkeyrunner.
  • Enter Infinite Loop
    • Call the commandQueque event queue maintainer instance described above to try to obtain an event from the queue
    • If the queue is triggered by an event, it immediately returns the runMonkeyCles method described in the previous article MonkeyRunner source code analysis startup to be called and executed.
    • If the queue has no event, call the socket read/write variable input described above to obtain a line of data (that is, a command string) sent by monkeyrunner in the socket)
    • Call the private method of translateCommand to call different monkeycommands for different commands to implement the translateCommand class interface. Translate the string command into the corresponding event and put it in the command queue (this command is not described above, next I will analyze)
    • If there is no command, or the signal is received, it will jump out of the loop. Otherwise, go back to the loop and start the above steps.
Let's take a look at how the private method of the translateCommand called to call the translateCommand interface of different commands:
    /**     * Translate the given command line into a MonkeyEvent.     *     * @param commandLine the full command line given.     */    private void translateCommand(String commandLine) {        Log.d(TAG, "translateCommand: " + commandLine);        List<String> parts = commandLineSplit(commandLine);        if (parts.size() > 0) {            MonkeyCommand command = COMMAND_MAP.get(parts.get(0));            if (command != null) {                MonkeyCommandReturn ret = command.translateCommand(parts, commandQueue);                handleReturn(ret);            }        }    }
It is easy to get the first value of the command string list that comes in by monkeyunner, and then convert the string to the corresponding MonkeyCommand implementation class through the COMMAND_MAP above, call its tranlsateCommand to translate the string command into the corresponding MonkeyEvent and store it in the event queue. For example, if the string from monkeyrunner is converted into a queue of ['Press ', 'key _ Code'], and the first member in the list is press, then the MonkeyCommand of COMMAND_MAP corresponding to the key of the "press" string is:
COMMAND_MAP.put("press", new PressCommand());
Therefore, we call the PressCommand MonkeyCommand interface implementation class's translateCommand method to convert the press command to the corresponding MonkeyKeyEvent.

4. Finally, we will combine the previous Monkey source code analysis running process to sort out the entire process of obtaining the event source and then executing the event:
  • Start Monkey and start calling the run Method
  • The ran method instantiates the specified event source based on the input parameters, for example, the MonkeySourceNetwork
  • The runMonkeyCyles method in the Monkey class starts to execute the loop fetch event.
    • Call the getNextEvent method of mEventSource maintained by the Monkey class to obtain an event. In this article, the getNextEvent method of the MonkeySourceNetwork instance described above is used.
      • The getNextEvent method reads an event from the quequeEvents maintained by CommandQueueImpl instance commandQueque.
      • If the event exists, return
      • The getNextEvent method starts the event Source Read listener. In this example, the above startServer method is used to listen to the socket connection and command data from monkeyrunner.
      • GetNextEvent method reads a command from the event Source
      • The getNextEvent method calls the corresponding MonkeyCommand interface to implement the class's translateCommand method. The string command is translated into the corresponding monkey event and saved to the quequeEvents queue maintained by commandQueque.
    • Execute the injectEvent method that returns the event
Well, the Event source analysis ends here. The next article will describe the Monkey Event to see how it executes these events.





How to analyze website source code

What do you mean by the analysis?
 
VB web page source code analysis

The regular expression is relatively stable.
However, if the content changes, it is easier to use the WebBrowser control to analyze the webpage by DOM.
It depends on the actual situation.

For example, use the WebBrowser control:
1. Download the webpage code. We recommend that you use inet to download the code (note the utf8 encoding problem)
2. process the code and remove scripts, iframe, and objects (otherwise, it will be difficult to bring up a dialog box when WebBrowser is used)
3. Send the processed code to WebBrowser,
4. Obtain the document from WebBrowser for DOM processing.
Sample Code:

'Get the document Object of webbrowser
Public Function getDocumentByHtml (html As String) As HTMLDocument
WebBrowser1.Silent = True
WebBrowser1.Navigate "about: blank" 'is cleared first.

Do Until WebBrowser1.ReadyState = 4' waiting for loading to complete
DoEvents
Loop

WebBrowser1.Document. write clearHtml (html)

Do Until WebBrowser1.ReadyState = 4' waiting for loading to complete
DoEvents
Loop

Set getDocumentByHtml = WebBrowser1.Document
End Function

After obtaining the document, you can use
The tr object obtained by document. getElementByID ("tr1855 ")
Then
Document. getElementByID ("tr1855"). getElementsByTagName ("td") then obtain the text in the table

For example, use a regular expression.
1. Download the webpage code. We recommend that you use inet to download the code (note the utf8 encoding problem)
2. Perform regular expression processing on the Code directly.

Sample Code:
Dim reg As New RegExp

Reg. IgnoreCase = True
Reg. Global = True
Reg. MultiLine = True

Reg. Pattern = "<tr. * id = \ x22tr1855 \ x22 [^ \ x00] *? </Tr> "'Regular Expression Code. Obtain the table code with the id tr1855.
Reg. Execute ("webpage Code") then returns the matchcollection type

Finally, the text in the td is extracted separately.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.