예제 #1
0
 def start(self, input_manager):
     """
     start producing events
     :param input_manager: instance of InputManager
     """
     count = 0
     while input_manager.enabled and count < input_manager.event_count:
         try:
             # make sure the first event is go to HOME screen
             # the second event is to start the app
             if count == 0:
                 event = KeyEvent(name="HOME")
             elif count == 1:
                 event = IntentEvent(self.app.get_start_intent())
             else:
                 event = self.generate_event()
             input_manager.add_event(event)
         except KeyboardInterrupt:
             break
         except InputInterruptedException as e:
             self.logger.warning("stop sending events: %s" % e)
             break
         # except RuntimeError as e:
         #     self.logger.warning(e.message)
         #     break
         except Exception as e:
             self.logger.warning("exception during sending events: %s" % e)
             import traceback
             traceback.print_exc()
             continue
         count += 1
예제 #2
0
    def generate_event_based_on_utg(self):
        """
        generate an event based on current device state
        note: ensure these fields are properly maintained in each transaction:
          last_event_flag, last_touched_view, last_state, exploited_views, state_transitions
        @return: InputEvent
        """
        self.save_state_transition(self.last_event_str, self.last_state,
                                   self.current_state)

        if self.device.is_foreground(self.app):
            # the app is in foreground, clear last_event_flag
            self.last_event_flag = EVENT_FLAG_STARTED
        else:
            number_of_starts = self.last_event_flag.count(EVENT_FLAG_START_APP)
            # If we have tried too many times but the app is still not started, stop DroidBot
            if number_of_starts > MAX_NUM_RESTARTS:
                raise InputInterruptedException("The app cannot be started.")

            # if app is not started, try start it
            if self.last_event_flag.endswith(EVENT_FLAG_START_APP):
                # It seems the app stuck at some state, and cannot be started
                # just pass to let viewclient deal with this case
                self.logger.info("The app had been restarted %d times.",
                                 number_of_starts)
                self.logger.info("Trying to restart app...")
                pass
            else:
                start_app_intent = self.app.get_start_intent()

                self.last_event_flag += EVENT_FLAG_START_APP
                self.last_event_str = EVENT_FLAG_START_APP
                return IntentEvent(start_app_intent)

        # select a view to click
        view_to_touch = self.select_a_view(self.current_state)

        # if no view can be selected, restart the app
        if view_to_touch is None:
            stop_app_intent = self.app.get_stop_intent()
            self.last_event_flag += EVENT_FLAG_STOP_APP
            self.last_event_str = EVENT_FLAG_STOP_APP
            return IntentEvent(stop_app_intent)

        view_to_touch_str = view_to_touch['view_str']
        if view_to_touch_str.startswith('BACK'):
            result = KeyEvent('BACK')
        else:
            result = TouchEvent(view=view_to_touch)

        self.last_event_flag += EVENT_FLAG_TOUCH
        self.last_event_str = view_to_touch_str
        self.save_explored_view(self.current_state, self.last_event_str)
        return result
    def generate_event(self):
        """
        generate an event
        @return:
        """

        # Get current device state
        self.current_state = self.device.get_current_state()
        if self.current_state is None:
            import time
            time.sleep(5)
            return KeyEvent(name="BACK")

        self.__update_utg()

        # update last view trees for humanoid
        if self.device.humanoid is not None:
            self.humanoid_view_trees = self.humanoid_view_trees + [
                self.current_state.view_tree
            ]
            if len(self.humanoid_view_trees) > 4:
                self.humanoid_view_trees = self.humanoid_view_trees[1:]

        event = None

        # if the previous operation is not finished, continue
        if len(self.script_events) > self.script_event_idx:
            event = self.script_events[
                self.script_event_idx].get_transformed_event(self)
            self.script_event_idx += 1

        # First try matching a state defined in the script
        if event is None and self.script is not None:
            operation = self.script.get_operation_based_on_state(
                self.current_state)
            if operation is not None:
                self.script_events = operation.events
                # restart script
                event = self.script_events[0].get_transformed_event(self)
                self.script_event_idx = 1

        if event is None:
            event = self.generate_event_based_on_utg()

        # update last events for humanoid
        if self.device.humanoid is not None:
            self.humanoid_events = self.humanoid_events + [event]
            if len(self.humanoid_events) > 3:
                self.humanoid_events = self.humanoid_events[1:]

        self.last_state = self.current_state
        self.last_event = event
        return event
예제 #4
0
    def set_possible_events(self):
        state = self.device.get_current_state()
        events = state.get_possible_input()
        #print(events)
        self.possible_events = events
        self.events_probs = list(np.ones(len(events)) / len(events))
        # if humanoid, sort events by humanoid model
        if self.device.humanoid is not None:
            self.possible_events, self.events_probs = self.policy.sort_inputs_by_humanoid(self.possible_events)
        if self.add_unexplored:
            # get first unexplored event and insert it at beginning of events. is pushed to index 1 if using POLICY_GREED_BFS
            # if no unexplored event, None is inserted
            unexplored_event = self.get_unexplored_event()
            self.possible_events.insert(0, unexplored_event)
            self.events_probs.insert(0, 0)

        if self.policy_type == POLICY_GREEDY_BFS:
            self.possible_events.insert(0, KeyEvent(name="BACK"))
            self.events_probs.insert(0, 0)
        elif self.policy_type == POLICY_GREEDY_DFS:
            self.possible_events.append(KeyEvent(name="BACK"))
            self.events_probs.append(0)
예제 #5
0
    def handle_none_current_state(self, current_state):
        if current_state is None:
            self.logger.warning("Failed to get current state in handle_none! Sleep for 5 seconds then back event (per droidbot source code)")
            import time
            time.sleep(5)
            new_event = KeyEvent(name="BACK")
            self.input_manager.add_event(new_event)
            current_state = self.device.get_current_state()

        while current_state is None:
            self.logger.warning("Failed to get current state again! Resetting Env")
            self.reset()
            time.sleep(2)
            current_state = self.device.get_current_state()

        return current_state
예제 #6
0
    def generate_event(self):
        """
        generate an event based on replay_output
        @return: InputEvent
        """
        import time
        while self.event_idx < len(self.event_paths) and \
              self.num_replay_tries < MAX_REPLY_TRIES:
            self.num_replay_tries += 1
            current_state = self.device.get_current_state()
            if current_state is None:
                time.sleep(5)
                self.num_replay_tries = 0
                return KeyEvent(name="BACK")

            curr_event_idx = self.event_idx
            while curr_event_idx < len(self.event_paths):
                event_path = self.event_paths[curr_event_idx]
                with open(event_path, "r") as f:
                    curr_event_idx += 1

                    try:
                        event_dict = json.load(f)
                    except Exception as e:
                        self.logger.info("Loading %s failed" % event_path)
                        continue

                    if event_dict["start_state"] != current_state.state_str:
                        continue

                    self.logger.info("Replaying %s" % event_path)
                    self.event_idx = curr_event_idx
                    self.num_replay_tries = 0
                    return InputEvent.from_dict(event_dict["event"])

            time.sleep(5)

        raise InputInterruptedException("No more record can be replayed.")
예제 #7
0
    def get_possible_input(self):
        """
        Get a list of possible input events for this state
        :return: list of InputEvent
        """
        if self.possible_events:
            return self.possible_events
        possible_events = []
        enabled_view_ids = []
        touch_exclude_view_ids = set()
        for view_dict in self.views:
            if self.__safe_dict_get(view_dict, 'enabled'):
                enabled_view_ids.append(view_dict['temp_id'])
        enabled_view_ids.reverse()

        for view_id in enabled_view_ids:
            if self.__safe_dict_get(self.views[view_id], 'clickable'):
                possible_events.append(TouchEvent(view=self.views[view_id]))
                touch_exclude_view_ids.add(view_id)
                touch_exclude_view_ids.union(
                    self.get_all_children(self.views[view_id]))

        for view_id in enabled_view_ids:
            if self.__safe_dict_get(self.views[view_id], 'scrollable'):
                possible_events.append(
                    ScrollEvent(view=self.views[view_id], direction="UP"))
                possible_events.append(
                    ScrollEvent(view=self.views[view_id], direction="DOWN"))
                possible_events.append(
                    ScrollEvent(view=self.views[view_id], direction="LEFT"))
                possible_events.append(
                    ScrollEvent(view=self.views[view_id], direction="RIGHT"))

        for view_id in enabled_view_ids:
            if self.__safe_dict_get(self.views[view_id], 'checkable'):
                possible_events.append(TouchEvent(view=self.views[view_id]))
                touch_exclude_view_ids.add(view_id)
                touch_exclude_view_ids.union(
                    self.get_all_children(self.views[view_id]))

        for view_id in enabled_view_ids:
            if self.__safe_dict_get(self.views[view_id], 'long_clickable'):
                possible_events.append(
                    LongTouchEvent(view=self.views[view_id]))

        for view_id in enabled_view_ids:
            if self.__safe_dict_get(self.views[view_id], 'editable'):
                touch_exclude_view_ids.add(view_id)
                # TODO figure out what event can be sent to editable views
                pass

        for view_id in enabled_view_ids:
            if view_id in touch_exclude_view_ids:
                continue
            children = self.__safe_dict_get(self.views[view_id], 'children')
            if children and len(children) > 0:
                continue
            possible_events.append(TouchEvent(view=self.views[view_id]))

        possible_events.append(KeyEvent(name="BACK"))

        self.possible_events = possible_events
        return possible_events
예제 #8
0
    def generate_event_based_on_utg(self):
        """
        generate an event based on current UTG
        @return: InputEvent
        """
        current_state = self.current_state
        if current_state.state_str in self.__missed_states:
            self.__missed_states.remove(current_state.state_str)

        if current_state.get_app_activity_depth(self.app) < 0:
            # If the app is not in the activity stack
            start_app_intent = self.app.get_start_intent()

            if self.__event_trace.endswith(EVENT_FLAG_START_APP + EVENT_FLAG_STOP_APP) \
                    or self.__event_trace.endswith(EVENT_FLAG_START_APP):
                self.__num_restarts += 1
            else:
                self.__num_restarts = 0

            if self.__num_restarts > MAX_NUM_RESTARTS:
                # If the app had been restarted too many times, abort
                msg = "The app had been restarted too many times."
                self.logger.info(msg)
                raise InputInterruptedException(msg)
            else:
                # Start the app
                self.__event_trace += EVENT_FLAG_START_APP
                self.logger.info("Trying to start the app...")
                return IntentEvent(intent=start_app_intent)

        elif current_state.get_app_activity_depth(self.app) > 0:
            # If the app is in activity stack but is not in foreground
            self.__num_steps_outside += 1

            if self.__num_steps_outside > MAX_NUM_STEPS_OUTSIDE:
                # If the app has not been in foreground for too long, try to go back
                go_back_event = KeyEvent(name="BACK")
                self.__event_trace += EVENT_FLAG_NAVIGATE
                self.logger.info("Going back to the app...")
                return go_back_event
        else:
            # If the app is in foreground
            self.__num_steps_outside = 0

        # Get all possible input events
        possible_events = current_state.get_possible_input()

        if self.random_input:
            random.shuffle(possible_events)

        # If there is an unexplored event, try the event first
        for input_event in possible_events:
            if not self.utg.is_event_explored(event=input_event,
                                              state=current_state):
                self.logger.info("Trying a unexplored event.")
                self.__event_trace += EVENT_FLAG_EXPLORE
                return input_event

        target_state = self.__get_nav_target(current_state)
        if target_state:
            event_path = self.utg.get_event_path(current_state=current_state,
                                                 target_state=target_state)
            if event_path and len(event_path) > 0:
                self.logger.info("Navigating to %s, %d steps left." %
                                 (target_state.state_str, len(event_path)))
                self.__event_trace += EVENT_FLAG_NAVIGATE
                return event_path[0]

        # If couldn't find a exploration target, stop the app
        stop_app_intent = self.app.get_stop_intent()
        self.logger.info(
            "Cannot find an exploration target. Trying to restart app...")
        self.__event_trace += EVENT_FLAG_STOP_APP
        return IntentEvent(intent=stop_app_intent)
예제 #9
0
    def generate_event_based_on_utg(self):
        """
        generate an event based on current UTG
        @return: InputEvent
        """
        #self.logger.info("Generating events in gym state: ")
        current_state = self.device.get_current_state() #self.current_state
        self.current_state = current_state
        self.logger.info("Current state: %s" % current_state.state_str)
        if current_state.state_str in self.__missed_states:
            self.__missed_states.remove(current_state.state_str)

        if current_state.get_app_activity_depth(self.app) < 0:
            # If the app is not in the activity stack
            start_app_intent = self.app.get_start_intent()

            # It seems the app stucks at some state, has been
            # 1) force stopped (START, STOP)
            #    just start the app again by increasing self.__num_restarts
            # 2) started at least once and cannot be started (START)
            #    pass to let viewclient deal with this case
            # 3) nothing
            #    a normal start. clear self.__num_restarts.

            if self.__event_trace.endswith(EVENT_FLAG_START_APP + EVENT_FLAG_STOP_APP) \
                    or self.__event_trace.endswith(EVENT_FLAG_START_APP):
                self.__num_restarts += 1
                self.logger.info("The app had been restarted %d times.", self.__num_restarts)
            else:
                self.__num_restarts = 0

            # pass (START) through
            if not self.__event_trace.endswith(EVENT_FLAG_START_APP):
                if self.__num_restarts > MAX_NUM_RESTARTS:
                    # If the app had been restarted too many times, enter random mode
                    msg = "The app had been restarted too many times. Entering random mode."
                    self.logger.info(msg)
                    self.__random_explore = True
                else:
                    # Start the app
                    self.__event_trace += EVENT_FLAG_START_APP
                    self.logger.info("Trying to start the app...")
                    return IntentEvent(intent=start_app_intent)

        elif current_state.get_app_activity_depth(self.app) > 0:
            # If the app is in activity stack but is not in foreground
            self.__num_steps_outside += 1

            if self.__num_steps_outside > MAX_NUM_STEPS_OUTSIDE:
                # If the app has not been in foreground for too long, try to go back
                if self.__num_steps_outside > MAX_NUM_STEPS_OUTSIDE_KILL:
                    stop_app_intent = self.app.get_stop_intent()
                    go_back_event = IntentEvent(stop_app_intent)
                else:
                    go_back_event = KeyEvent(name="BACK")
                self.__event_trace += EVENT_FLAG_NAVIGATE
                self.logger.info("Going back to the app...")
                return go_back_event
        else:
            # If the app is in foreground
            self.__num_steps_outside = 0

        # Get all possible input events
        possible_events = current_state.get_possible_input()

        if self.random_input:
            random.shuffle(possible_events)

        if self.search_method == POLICY_GREEDY_DFS:
            possible_events.append(KeyEvent(name="BACK"))
        elif self.search_method == POLICY_GREEDY_BFS:
            possible_events.insert(0, KeyEvent(name="BACK"))

        # get humanoid result, use the result to sort possible events
        # including back events
        if self.device.humanoid is not None:
            possible_events = self.__sort_inputs_by_humanoid(possible_events)

        # If there is an unexplored event, try the event first
        for input_event in possible_events:
            if not self.utg.is_event_explored(event=input_event, state=current_state):
                self.logger.info("Trying an unexplored event.")
                self.__event_trace += EVENT_FLAG_EXPLORE
                return input_event

        target_state = self.__get_nav_target(current_state)
        if target_state:
            event_path = self.utg.get_event_path(current_state=current_state, target_state=target_state)
            if event_path and len(event_path) > 0:
                self.logger.info("Navigating to %s, %d steps left." % (target_state.state_str, len(event_path)))
                self.__event_trace += EVENT_FLAG_NAVIGATE
                return event_path[0]

        if self.__random_explore:
            self.logger.info("Trying random event.")
            random.shuffle(possible_events)
            return possible_events[0]

        # If couldn't find a exploration target, stop the app
        stop_app_intent = self.app.get_stop_intent()
        self.logger.info("Cannot find an exploration target. Trying to restart app...")
        self.__event_trace += EVENT_FLAG_STOP_APP
        return IntentEvent(intent=stop_app_intent)
예제 #10
0
 def reset_home(self):
     home_event = KeyEvent(name="HOME")
     #self.logger.info("Entering reset_home, going to home screen")
     self.__event_trace += "+home_reset"
     return home_event
예제 #11
0
    def check_gym_event(self, event, event_trace_str = "+NA"):
        #self.logger.info("checking gym event from env.step")
        current_state = self.device.get_current_state()
        self.current_state = current_state
        #self.logger.info("Current state: %s" % current_state.state_str)
        if current_state.state_str in self.__missed_states:
            self.__missed_states.remove(current_state.state_str)

        if current_state.get_app_activity_depth(self.app) < 0:
            # If the app is not in the activity stack
            start_app_intent = self.app.get_start_intent()

            # It seems the app stucks at some state, has been
            # 1) force stopped (START, STOP)
            #    just start the app again by increasing self.__num_restarts
            # 2) started at least once and cannot be started (START)
            #    pass to let viewclient deal with this case
            # 3) nothing
            #    a normal start. clear self.__num_restarts.

            if self.__event_trace.endswith(EVENT_FLAG_START_APP + EVENT_FLAG_STOP_APP) \
                    or self.__event_trace.endswith(EVENT_FLAG_START_APP):
                self.__num_restarts += 1
                self.logger.info("The app had been restarted %d times.", self.__num_restarts)
            else:
                self.__num_restarts = 0

            # pass (START) through
            if not self.__event_trace.endswith(EVENT_FLAG_START_APP):
                if self.__num_restarts > MAX_NUM_RESTARTS:
                    # If the app had been restarted too many times, enter random mode
                    msg = "The app had been restarted too many times. Enabling random mode."
                    self.logger.info(msg)
                    self.__random_explore = True
                else:
                    # Start the app
                    self.__event_trace += EVENT_FLAG_START_APP
                    self.logger.info("Trying to start the app...")
                    return IntentEvent(intent=start_app_intent)

        elif current_state.get_app_activity_depth(self.app) > 0:
            # If the app is in activity stack but is not in foreground
            self.__num_steps_outside += 1

            if self.__num_steps_outside > MAX_NUM_STEPS_OUTSIDE:
                # If the app has not been in foreground for too long, try to go back
                if self.__num_steps_outside > MAX_NUM_STEPS_OUTSIDE_KILL:
                    stop_app_intent = self.app.get_stop_intent()
                    go_back_event = IntentEvent(stop_app_intent)
                else:
                    go_back_event = KeyEvent(name="BACK")
                self.__event_trace += EVENT_FLAG_NAVIGATE
                self.logger.info("Going back to the app...")
                return go_back_event
        else:
            # If the app is in foreground
            self.__num_steps_outside = 0

        #self.logger.info("Passed initial steps, returning the event for input manager")
        self.__event_trace += event_trace_str

        #update the utg
        #self.current_state = self.device.get_current_state() #updated up above
        self.__update_utg()
        self.last_state = self.current_state
        self.last_event = event

        return event
예제 #12
0
    def generate_event_based_on_utg(self):
        """
        generate an event based on current UTG
        @return: InputEvent
        """
        current_state = self.current_state
        if current_state.state_str in self.__missed_states:
            self.__missed_states.remove(current_state.state_str)

        if current_state.get_app_activity_depth(self.app) < 0:
            # If the app is not in the activity stack
            start_app_intent = self.app.get_start_intent()

            if self.__event_trace.endswith(EVENT_FLAG_START_APP + EVENT_FLAG_STOP_APP) \
                    or self.__event_trace.endswith(EVENT_FLAG_START_APP):
                self.__num_restarts += 1
            else:
                self.__num_restarts = 0

            if self.__num_restarts > MAX_NUM_RESTARTS:
                # If the app had been restarted too many times, abort
                msg = "The app had been restarted too many times."
                self.logger.info(msg)
                raise InputInterruptedException(msg)
            else:
                # Start the app
                self.__event_trace += EVENT_FLAG_START_APP
                self.logger.info("Trying to start the app...")
                return IntentEvent(intent=start_app_intent)

        elif current_state.get_app_activity_depth(self.app) > 0:
            # If the app is in activity stack but is not in foreground
            self.__num_steps_outside += 1

            if self.__num_steps_outside > MAX_NUM_STEPS_OUTSIDE:
                # If the app has not been in foreground for too long, try to go back
                go_back_event = KeyEvent(name="BACK")
                self.__event_trace += EVENT_FLAG_NAVIGATE
                self.logger.info("Going back to the app...")
                return go_back_event
        else:
            # If the app is in foreground
            self.__num_steps_outside = 0

        curr_screenshot = current_state.device.take_screenshot()
        new_screenshot = str(curr_screenshot).replace("/temp/", "/all_screenshots/")

        directory = os.path.dirname(new_screenshot)

        if not os.path.exists(directory):
            os.mkdir(directory)

        move(curr_screenshot, new_screenshot)

        # Get all possible input events
        all_views = current_state.views
        actionable_views = filter(lambda x : x["enabled"] and x["visible"] and
                                             (x["clickable"] or x["scrollable"] or x["checkable"] or x["long_clickable"]),
                                  all_views)

        items = []
        for view in actionable_views:
            data = {"class": view["class"]}

            if view["parent"] >= 0:
                data["parent"] = all_views[view["parent"]]["class"]
            else:
                data["parent"] = "none"

            if len(view["children"]) > 1:
                data["children2"] = all_views[view["children"][1]]["class"]
            else:
                data["children2"] = "none"

            if len(view["children"]) > 0:
                data["children1"] = all_views[view["children"][0]]["class"]
            else:
                data["children1"] = "none"

            items.append(data)

        predictions = ModelBased.classify(items)
        selected_idx = ModelBased.select(predictions)

        possible_events = current_state.get_possible_input()

        if len(possible_events) > 0:
            # If it was not possible to classify fall back to purely random strategy
            if selected_idx >= 0:
                selected_widget = actionable_views[selected_idx]
                chance = random.random()

                tmp_events = [x
                              for x in possible_events
                              if ((not isinstance(x, UIEvent)) and (chance < 0.2)) or
                                 (isinstance(x, UIEvent) and UtgRandomWidgetPolicy.are_equal(x.view, selected_widget))]

                if len(tmp_events) > 0:
                    possible_events = tmp_events

            random.shuffle(possible_events)
            self.logger.info("Trying a random event.")
            self.__event_trace += EVENT_FLAG_EXPLORE
            input_event = possible_events[0]
            return input_event

        # If couldn't find a exploration target, stop the app
        stop_app_intent = self.app.get_stop_intent()
        self.logger.info("Cannot find an exploration target. Trying to restart app...")
        self.__event_trace += EVENT_FLAG_STOP_APP
        return IntentEvent(intent=stop_app_intent)
예제 #13
0
    def start(self, input_manager):
        """
        start producing events
        :param input_manager: instance of InputManager
        """
        count = 0
        network_monitoring = False
        while input_manager.enabled and count < input_manager.event_count:
            try:
                # make sure the first event is go to HOME screen
                # the second event is to start the app

                if count == 0 and self.master is None:
                    event = KeyEvent(name="HOME")
                elif count == 1 and self.master is None:
                    event = IntentEvent(self.app.get_start_intent())
                else:
                    event = self.generate_event()

                if network_monitoring == True and hasattr(event,"intent"):
                    process_strace.terminate()
                    network_monitoring = False

                input_manager.add_event(event)
                if hasattr(event,"intent"):
                    current_processes = self.device.adb.shell("ps").split("\r\n")
                    import re
                    for currentProcess in current_processes:
                        if currentProcess.find(self.app.package_name) != -1:
                            pattern_result = re.search(r"\s\d+\s", currentProcess)
                            pid = pattern_result.group(0)
                            break

                    from subprocess import Popen, PIPE
                    network_monitoring=True
                    process_strace = Popen(['adb' , 'shell'] , stdin=PIPE)
                    process_strace.stdin.write('su\n')
                    process_strace.stdin.flush()
                    if count==1:
                         monitor_command = "strace -f -e trace=network -s 10000 -p " + pid + " &> /mnt/user/0/primary/networkResults"
                    else:
                        monitor_command = "strace -f -e trace=network -s 10000 -p " + pid + " &>> /mnt/user/0/primary/networkResults"
                    process_strace.stdin.write(monitor_command+'\n')
                    process_strace.stdin.flush()





            except KeyboardInterrupt:
                break
            except InputInterruptedException as e:
                self.logger.warning("stop sending events: %s" % e)
                break
            # except RuntimeError as e:
            #     self.logger.warning(e.message)
            #     break
            except Exception as e:
                self.logger.warning("exception during sending events: %s" % e)
                import traceback
                traceback.print_exc()
                continue
            count += 1

        process_strace.terminate()
        process_grep = Popen(['adb', 'shell'], stdout=PIPE, stdin=PIPE)
        process_grep.stdin.write('su\n')
        process_grep.stdin.flush()
        process_grep.stdin.write('grep -a HTTP/ /mnt/user/0/primary/networkResults' + '\n')
        process_grep.stdin.flush()
        stdout_string, stderr_string = process_grep.communicate()
        process_grep.terminate()
        import os

        network_file = open(os.path.join(self.device.output_dir, "HTTPLines.txt"), 'w')
        network_file.write(stdout_string)  # python will convert \n to os.linesep
        network_file.close()  # you can omit in most cases as the destructor will call it
    def generate_event_based_on_utg(self):
        """
        generate an event based on current UTG
        @return: InputEvent
        """
        current_state = self.current_state
        self.logger.info("Current state: %s" % current_state.state_str)
        if current_state.state_str in self.__missed_states:
            self.__missed_states.remove(current_state.state_str)

        if current_state.get_app_activity_depth(self.app) < 0:
            # If the app is not in the activity stack
            start_app_intent = self.app.get_start_intent()

            # It seems the app stucks at some state, has been
            # 1) force stopped (START, STOP)
            #    just start the app again by increasing self.__num_restarts
            # 2) started at least once and cannot be started (START)
            #    pass to let viewclient deal with this case
            # 3) nothing
            #    a normal start. clear self.__num_restarts.

            if self.__event_trace.endswith(EVENT_FLAG_START_APP + EVENT_FLAG_STOP_APP) \
                    or self.__event_trace.endswith(EVENT_FLAG_START_APP):
                self.__num_restarts += 1
                self.logger.info("The app had been restarted %d times.",
                                 self.__num_restarts)
            else:
                self.__num_restarts = 0

            # pass (START) through
            if not self.__event_trace.endswith(EVENT_FLAG_START_APP):
                if self.__num_restarts > MAX_NUM_RESTARTS:
                    # If the app had been restarted too many times, enter random mode
                    msg = "The app had been restarted too many times. Entering random mode."
                    self.logger.info(msg)
                    self.__random_explore = True
                else:
                    # Start the app
                    self.__event_trace += EVENT_FLAG_START_APP
                    self.logger.info("Trying to start the app...")
                    return IntentEvent(intent=start_app_intent)

        elif current_state.get_app_activity_depth(self.app) > 0:
            # If the app is in activity stack but is not in foreground
            self.__num_steps_outside += 1

            if self.__num_steps_outside > MAX_NUM_STEPS_OUTSIDE:
                # If the app has not been in foreground for too long, try to go back
                if self.__num_steps_outside > MAX_NUM_STEPS_OUTSIDE_KILL:
                    stop_app_intent = self.app.get_stop_intent()
                    go_back_event = IntentEvent(stop_app_intent)
                else:
                    go_back_event = KeyEvent(name="BACK")
                self.__event_trace += EVENT_FLAG_NAVIGATE
                self.logger.info("Going back to the app...")
                return go_back_event
        else:
            # If the app is in foreground
            self.__num_steps_outside = 0

        # Get all possible input events
        possible_events = current_state.get_possible_input()

        count = 0
        for activity in self.edit_text_value:
            count = count + len(self.edit_text_value[activity])

        print("Possible events: " + str(len(possible_events)))
        print("Editable Text Events: " + str(count))
        """
        for activity in self.edit_text_value:
            string = activity + ": "
            for resource_id in self.edit_text_value[activity]:
                string = string + resource_id + " = " + str(self.edit_text_value[activity][resource_id].text) + ", "
            print(string)
        """

        variation = False
        activity_variation = list()
        event_added = list()

        for event in possible_events:
            if isinstance(event, SetTextEvent):
                activity = event.view["activity"]
                resource_id = event.view["resource_id"]
                if activity not in self.edit_text_value or resource_id not in self.edit_text_value[
                        activity]:
                    if activity not in self.edit_text_value:
                        self.edit_text_value[activity] = dict()
                    self.edit_text_value[activity][resource_id] = event
                    event_added.append(event)
                    variation = True
                    if activity not in activity_variation:
                        activity_variation.append(activity)

        if variation:
            for activity in activity_variation:
                event_list = list(self.edit_text_value[activity].values())
                view_text_association = ViewTextAssociation(event_list)
                complete_event_list = view_text_association.GetSetTextEvents()
                for new_event in event_added:
                    for event in complete_event_list:
                        activity = event.view["activity"]
                        resource_id = event.view["resource_id"]
                        if new_event.view["resource_id"] == event.view[
                                "resource_id"]:
                            self.edit_text_value[activity][resource_id] = event

        if self.random_input:
            random.shuffle(possible_events)

        if self.search_method == POLICY_GREEDY_DFS:
            possible_events.append(KeyEvent(name="BACK"))
        elif self.search_method == POLICY_GREEDY_BFS:
            possible_events.insert(0, KeyEvent(name="BACK"))

        # get humanoid result, use the result to sort possible events
        # including back events
        if self.device.humanoid is not None:
            possible_events = self.__sort_inputs_by_humanoid(possible_events)

        new_input_event = None
        if self.last_event is not None and self.last_event.event_type == 'touch' and \
                self.last_event.view['class'] == 'android.widget.EditText':
            resource_id = self.last_event.view['resource_id']
            for input_event in possible_events:
                if isinstance(input_event, SetTextEvent) and \
                        input_event.view['resource_id'] == resource_id:
                    new_input_event = input_event
                    break

        last_event_edit = False
        if self.last_event is not None and self.last_event.event_type == 'set_text' and \
                self.last_event.view['class'] == 'android.widget.EditText':
            resource_id = self.last_event.view['resource_id']
            last_event_edit = True

        # If there is an unexplored event, try the event first
        for input_event in possible_events:
            if new_input_event is not None:
                input_event = new_input_event
            """
            elif last_event_edit:
                if input_event.view['resource_id'] == resource_id:
                    continue
            """
            if not self.utg.is_event_explored(event=input_event,
                                              state=current_state):
                self.logger.info("Trying an unexplored event.")
                self.__event_trace += EVENT_FLAG_EXPLORE
                if isinstance(input_event, SetTextEvent):
                    resource_id = input_event.view["resource_id"]
                    activity = input_event.view["activity"]
                    for event_resource_id in self.edit_text_value[activity]:
                        if resource_id == event_resource_id:
                            input_event.text = self.edit_text_value[activity][
                                event_resource_id].text
                print(input_event)
                return input_event

        target_state = self.__get_nav_target(current_state)
        if target_state:
            event_path = self.utg.get_event_path(current_state=current_state,
                                                 target_state=target_state)
            if event_path and len(event_path) > 0:
                self.logger.info("Navigating to %s, %d steps left." %
                                 (target_state.state_str, len(event_path)))
                self.__event_trace += EVENT_FLAG_NAVIGATE
                return event_path[0]

        if self.__random_explore:
            self.logger.info("Trying random event.")
            random.shuffle(possible_events)
            return possible_events[0]

        # If couldn't find a exploration target, stop the app
        stop_app_intent = self.app.get_stop_intent()
        self.logger.info(
            "Cannot find an exploration target. Trying to restart app...")
        self.__event_trace += EVENT_FLAG_STOP_APP
        return IntentEvent(intent=stop_app_intent)
예제 #15
0
    def get_possible_input(self):
        """
        Get a list of possible input events for this state
        :return: list of InputEvent
        """
        if self.possible_events:
            return [] + self.possible_events
        possible_events = []
        enabled_view_ids = []
        touch_exclude_view_ids = set()
        for view_dict in self.views:
            # exclude navigation bar if exists
            if self.__safe_dict_get(view_dict, 'enabled') and \
               self.__safe_dict_get(view_dict, 'resource_id') not in \
               ['android:id/navigationBarBackground',
                'android:id/statusBarBackground']:
                enabled_view_ids.append(view_dict['temp_id'])
        enabled_view_ids.reverse()

        for view_id in enabled_view_ids:
            if self.__safe_dict_get(self.views[view_id], 'clickable'):
                possible_events.append(TouchEvent(view=self.views[view_id]))
                touch_exclude_view_ids.add(view_id)
                touch_exclude_view_ids.union(
                    self.get_all_children(self.views[view_id]))

        for view_id in enabled_view_ids:
            if self.__safe_dict_get(self.views[view_id], 'scrollable'):
                possible_events.append(
                    ScrollEvent(view=self.views[view_id], direction="UP"))
                possible_events.append(
                    ScrollEvent(view=self.views[view_id], direction="DOWN"))
                possible_events.append(
                    ScrollEvent(view=self.views[view_id], direction="LEFT"))
                possible_events.append(
                    ScrollEvent(view=self.views[view_id], direction="RIGHT"))

        for view_id in enabled_view_ids:
            if self.__safe_dict_get(self.views[view_id],
                                    'checkable') and not self.__safe_dict_get(
                                        self.views[view_id], 'clickable'):
                possible_events.append(TouchEvent(view=self.views[view_id]))
                touch_exclude_view_ids.add(view_id)
                touch_exclude_view_ids.union(
                    self.get_all_children(self.views[view_id]))

        for view_id in enabled_view_ids:
            if self.__safe_dict_get(self.views[view_id], 'long_clickable'):
                possible_events.append(
                    LongTouchEvent(view=self.views[view_id]))

        for view_id in enabled_view_ids:
            if self.__safe_dict_get(self.views[view_id], 'editable'):
                possible_events.append(
                    SetTextEvent(view=self.views[view_id], text="HelloWorld"))
                touch_exclude_view_ids.add(view_id)
                # TODO figure out what event can be sent to editable views
                pass

        for view_id in enabled_view_ids:
            if view_id in touch_exclude_view_ids:
                continue
            children = self.__safe_dict_get(self.views[view_id], 'children')
            if children and len(children) > 0:
                continue
            possible_events.append(TouchEvent(view=self.views[view_id]))

        # For old Android navigation bars
        possible_events.append(KeyEvent(name="MENU"))
        state_now = self.device.get_current_state()
        #print('BASIC SOURCE')
        events, event_ids = [], []

        for i, event in enumerate(possible_events):
            event_str = str(type(event)) + '_' + event.get_event_str(state_now)
            if event_str in event_ids:
                continue
            events.append(event)
            event_ids.append(event_str)

        self.possible_events = events
        return [] + events