Esempio n. 1
0
def push_and_start_frida_server(adb: ADB):
    """
    Push and start adb server on device
    Parameters
    ----------
    adb

    Returns
    -------

    """
    frida_server = os.path.join(os.getcwd(), "resources", "frida-server", "frida-server")

    try:
        adb.execute(['root'])
    except Exception as e:
        adb.kill_server()
        logger.error("Error on adb {}".format(e))

    logger.info("Push frida server")
    try:
        adb.push_file(frida_server, "/data/local/tmp")
    except Exception as e:
        pass
    logger.info("Add execution permission to frida-server")
    chmod_frida = ["chmod 755 /data/local/tmp/frida-server"]
    adb.shell(chmod_frida)
    logger.info("Start frida server")
    start_frida = ["cd /data/local/tmp && ./frida-server &"]
    adb.shell(start_frida, is_async=True)
    time.sleep(4)
def push_api_monitor_xposed(adb: ADB, package_name: str, dir_hook_file: str):
    """
    push file on emulator needed to api monitor

    Parameters
    ----------
    adb
    package_name
    dir_hook_file

    Returns
    -------

    """
    logger.info("Push files needed to API Monitor")
    adb.push_file(os.path.join(dir_hook_file, "hooks.json"), "/data/local/tmp")
    adb.shell(['echo', '"{0}"'.format(package_name), '>', '/data/local/tmp/package.name'])
Esempio n. 3
0
def ping():
    trytime = 30
    success = 0
    adb = ADB()
    cmd = "ping -c 4 {0} | grep -q 'ttl=' && echo '{0} ok' || echo '{0} failed'".format(
        '61.135.169.125')
    print(cmd)
    for i in range(trytime):
        result = adb.shell(cmd)
        if 'ok' in result[1]: success += 1
        print(result)
    return success
Esempio n. 4
0
def push_and_start_frida_server(adb: ADB):
    """
    Push and start adb server on device
    Parameters
    ----------
    adb

    Returns
    -------

    """
    frida_server = os.path.join(os.path.dirname(__file__), "resources",
                                "frida-server", "frida-server")

    cmd_output = adb.shell("ps -e | grep frida".split())

    if "frida-server" in cmd_output:
        logger.warning("[*] frida-server is already running on device")
        return

    try:
        adb.execute(["root"])
    except Exception as e:
        adb.kill_server()
        logger.error("Error on adb {}".format(e))

    logger.info("[*] Push frida server")
    try:
        adb.push_file(frida_server, "/data/local/tmp")
    except Exception as e:
        pass
    logger.info("[*] Add execution permission to frida-server")
    chmod_frida = ["chmod 755 /data/local/tmp/frida-server"]
    adb.shell(chmod_frida)
    logger.info("Start frida server")
    start_frida = ["cd /data/local/tmp && ./frida-server &"]
    adb.shell(start_frida, is_async=True)
    time.sleep(4)
Esempio n. 5
0
def loopInit():
    powerUsbController.OPEN_MAIN_POWER()
    powerUsbController.OPEN_KL15()
    powerUsbController.USB_ON()
    time.sleep(20)
    logging.info("swith to Diagnostics Mode")
    openADB(TBOX_IP, TBOX_DIAG_KEY)
    time.sleep(20)
    powerUsbController.SHUTDOWN_KL15()
    time.sleep(2)
    adb = ADB()
    #adb.stopAdb()
    #adb.startAdb()
    logging.info(
        "adb shell zte_topsw_mcutest 29 02000600060002000200020004000000")
    ret = adb.shell("zte_topsw_mcutest 29 02000600060002000200020004000000",
                    TBOX_ADB_SN)
    if (0 != ret[0]):
        raise Exception("send adb shell zte_topsw_mcutest failed! " + ret[2])
    logging.info(ret[1])
    time.sleep(1)
Esempio n. 6
0
def push_and_start_frida_server_google_emulator(adb: ADB):
    """
    Parameters
    ----------
    adb
    Returns
    -------
    """
    frida_server = os.path.join(os.path.dirname(__file__), "resources",
                                "frida-server-15-1-17", "frida-server")

    logger.info("[*] Checking if frida-server is already running")
    cmd_output = adb.shell("ps -e | grep frida")

    if "frida-server" in cmd_output:
        logger.warning("[*] frida-server is already running on device")
        return

    logger.info("[*] Push frida-server (google-emulator)")
    try:
        adb.push_file(frida_server, "/sdcard")
        adb.shell_su("mv /sdcard/frida-server /data/local/tmp/frida-server")
    except Exception as e:
        pass

    cmd_set_enforce = "setenforce 0"
    adb.shell_su(cmd_set_enforce)

    cmd_enforce_echo = "echo 0 > /sys/fs/selinux/enforce"
    adb.shell_su(cmd_enforce_echo)

    chmod_frida = "chmod 755 /data/local/tmp/frida-server"
    adb.shell_su(chmod_frida)
    logger.info("[*] Start frida server")
    start_frida = "/data/local/tmp/frida-server &"
    adb.shell_su(start_frida, is_async=True)
    time.sleep(4)
def start_analysis(list_apps: list, timeout_privacy: int, max_actions: int, type: str, emulator_name: str):
    logger.info("Start Analysis of {} apps".format(len(list_apps)))
    start = time.time()
    stats = Statistic(type)

    if type == "random":
        type = start_appium_node(type)

    logger.info("Upload model p3 detector")
    # upload model
    pdetector = PredictionModel()
    logger.info("P3detector model uploaded")

    # start analysis
    count = 0
    tentative = 0
    num_log = len(glob.glob(os.path.join(os.getcwd(), "logs", "log_analysis_*")))

    log_analysis_file = os.path.join(os.getcwd(), "logs", "log_analysis_{}.json".format(num_log + 1))
    log_permission_file = os.path.join(os.getcwd(), "logs", "permissions_stats_{}.json".format(num_log + 1))
    log_trackers_file = os.path.join(os.getcwd(), "logs", "tracker_stats_{}.json".format(num_log + 1))

    while count < len(list_apps):

        app = list_apps[count]
        dict_analysis_app = {}
        md5_app = md5(app)

        dir_result = os.path.join(os.getcwd(), "logs", md5_app)
        if not os.path.exists(dir_result):
            os.makedirs(dir_result)

        try:

            dict_analysis_app["md5"] = md5_app
            apk_object = APK(app)
            dict_analysis_app["package_name"] = apk_object.get_package()

            if not check_app_already_analyzed_md5(md5_app) or tentative > 0:

                logger.info("3PDroid start Analysis {}".format(app))
                write_package_name_and_md5(apk_object.get_package(), md5_app,
                                           os.path.join(os.getcwd(), "logs", "package_md5.txt"))
                # start emulator
                r_start_emulator = requests.get("{}/start/{}".format(LOCAL_URL_EMULATOR, emulator_name))
                # if the emulator star ok
                if r_start_emulator.status_code == 200:
                    # get trackers libraries and list permissions
                    logger.info("Start emulator ok")
                    logger.info("Get application information")
                    app_trackers, app_permissions_list, api_to_monitoring_trackers, application, dict_analysis_app = app_analyzer. \
                        analyze_apk_androguard(app, md5_app, dict_analysis_app)
                    # get permissions privacy relevant
                    logger.info("Package name {}".format(application.get_package()))
                    dict_analysis_app["package_name"] = application.get_package()
                    logger.info("MD5 {}".format(md5_app))

                    logger.info("Get permission-api mapping")
                    permissions_api_mapping = app_analyzer.get_api_related_to_permission_privacy_relevant()
                    logger.info("Creation list api to be monitored during dynamic analysis")
                    list_api_to_monitoring = app_analyzer.create_list_api_to_monitoring_from_file(
                        permissions_api_mapping,
                        app_permissions_list,
                        app_trackers)

                    # if API == 0 --> app is cleaned
                    if len(list_api_to_monitoring) == 0:
                        logger.info("Application does not need privacy policy page, "
                                    "close the emulator and "
                                    "pass to the next application")
                        # write on file
                        file_name = md5_app
                        dir_result = os.path.join(os.getcwd(), "logs", file_name)
                        dict_analysis_app["dynamic_analysis_needed"] = False
                        with open(os.path.join(dir_result, "{}.json".format(file_name)), "w") as json_file:
                            json.dump(dict_analysis_app, json_file, indent=4)

                        count += 1
                        r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name))
                        # UPDATE STATS
                        logger.info("Update stats")
                        stats.update_stats_permission(app_permissions_list)
                        stats.update_stats_trackers(app_trackers)
                        stats.add_app_cleaned()
                        # STORE INFORMATION
                        logger.info(stats.stats_trackers)
                        logger.info(stats.stats_permission)
                        # write on file
                        stats.write_on_file(log_analysis_file, count)
                        stats.write_stats_permissions(log_permission_file)
                        stats.write_stats_trackers(log_trackers_file)
                        shutil.move(app, os.path.join(os.getcwd(), "apps_analyzed"))
                        continue

                    # APP should be analyzed in a dynamic way
                    logger.info("Number of APIs to monitoring: {}".format(len(list_api_to_monitoring)))
                    file_name = md5_app
                    dir_result = os.path.join(os.getcwd(), "logs", file_name)
                    dict_analysis_app["api_to_monitoring_all"] = len(list_api_to_monitoring)
                    with open(os.path.join(dir_result, "{}.json".format(file_name)), "w") as json_file:
                        json.dump(dict_analysis_app, json_file, indent=4)
                    # disable verify installer and set correct time
                    time.sleep(5)
                    logger.info("Set correct time on emulator")
                    adb = ADB()
                    adb.kill_server()
                    adb.connect()
                    time.sleep(2)
                    try:
                        command_settings_verify = ["settings put global verifier_verify_adb_installs 0"]
                        adb.shell(command_settings_verify)
                        date_command = ['su 0 date {0}; am broadcast -a android.intent.action.TIME_SET'.
                                            format(time.strftime('%m%d%H%M%Y.%S'))]
                        adb.shell(date_command)
                    except Exception as e:
                        logger.error("Exception as e {}, restart and re-connect to emulator".format(e))
                        adb.kill_server()
                        adb.connect()
                        command_settings_verify = ["settings put global verifier_verify_adb_installs 0"]
                        adb.shell(command_settings_verify)
                        date_command = ['su 0 date {0}; am broadcast -a android.intent.action.TIME_SET'.
                                            format(time.strftime('%m%d%H%M%Y.%S'))]
                        adb.shell(date_command)

                    dir_hook_file = os.path.join(os.getcwd(), "hook", md5_app)
                    logger.info("Creation hook dir frida")

                    if not os.path.exists(dir_hook_file):
                        os.makedirs(dir_hook_file)
                    hook_is_created = app_analyzer.create_api_list_frida(list_api_to_monitoring,
                                                                         os.path.join(dir_hook_file, "frida_api.txt"))
                    frida_monitoring.push_and_start_frida_server(adb)
                    frida_monitoring.set_file_log_frida(os.path.join(os.getcwd(), "logs",
                                                                     md5_app, "monitoring_api_{}.json".format(md5_app)))

                    frida_monitoring.clean_list_json_api_invoked()
                    signal.signal(signal.SIGALRM, handler_timeout)
                    signal.alarm(MAX_TIME_ANALYSIS)
                    result_app, dict_analysis_app = dynamic_testing_environment.start_analysis(type_analysis=type,
                                                                                               app=app,
                                                                                               max_actions=max_actions,
                                                                                               timeout_privacy=timeout_privacy,
                                                                                               pdetector=pdetector,
                                                                                               md5_app=md5_app,
                                                                                               frida_monitoring=frida_monitoring,
                                                                                               dict_analysis_app=dict_analysis_app)

                    # END DYNAMIC ANALYSIS NOW STORE DATA
                    result_directory = os.path.join(os.getcwd(), "logs", md5_app)
                    if not os.path.exists(result_directory):
                        os.makedirs(result_directory)

                    logger.info("Analysis api invoked during dynamic analysis")
                    # Get API Invoked
                    list_json_api_invoked = frida_monitoring.get_list_api_invoked()
                    # set_list_json_api_invoked = list(set(list_json_api_invoked))
                    logger.info("Api invoked during dynamic analysis {}".format(len(list_json_api_invoked)))

                    # store on json file the api invoked
                    if len(list_json_api_invoked) > 0:
                        file_log_frida = frida_monitoring.get_file_log_frida()
                        with open(file_log_frida, "w") as outfile_api:
                            json.dump(list_json_api_invoked, outfile_api, indent=4)

                    # Action not needed
                    # DETECT IF THE APP IS COMPLIANT OR NOT WITH GOOGLE PLAY STORE
                    app_is_compliant = result_app.detected and not (result_app.back_button_change_page or
                                                                    result_app.home_button_change_page or
                                                                    len(list_json_api_invoked) > 0
                                                                    )

                    dict_analysis_app["api_invoked_during_dynamic_analysis"] = len(list_json_api_invoked)
                    if app_is_compliant:
                        stats.add_app_compliant()
                    else:
                        stats.add_app_not_compliant()
                    dict_analysis_app["app_is_compliant_with_google_play_store"] = app_is_compliant
                    dict_analysis_app["app_analyzed"] = True
                    dict_analysis_app["num_tentative"] = tentative + 1

                    write_json_file_log(md5_app, dict_analysis_app)

                    stats.add_api_privacy_relevant_invoked(len(list_json_api_invoked))

                    # r_reset_emulator = requests.get("{}/reset/{}".format(LOCAL_URL_EMULATOR, emulator_name))
                    r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name))

                    # UPDATE stats analysis
                    logger.info("Update stats")
                    stats.list_max_actions.append(result_app.max_actions)
                    stats.update_value_dynamic_analysis(result_app)
                    stats.update_stats_permission(app_permissions_list)
                    stats.update_stats_trackers(app_trackers)

                    # debug
                    logger.info(stats.stats_trackers)
                    logger.info(stats.stats_permission)

                    # write on file
                    count += 1
                    tentative = 0

                    stats.write_on_file(log_analysis_file, count)
                    stats.write_stats_permissions(log_permission_file)
                    stats.write_stats_trackers(log_trackers_file)
                    logger.info("End update stats")
                    logger.info("3PDroid end analysis")
                    str_end_file = "*" * 20
                    logger.info("{}\n\n".format(str_end_file))
                    shutil.move(app, os.path.join(os.getcwd(), "apps_analyzed"))
                    
                else:

                    tentative += 1
                    if tentative < MAX_TENTATIVE:
                        logger.error("Unable to start emulator, try again this app")
                        str_end_file = "*" * 20
                        logger.info("{}\n\n".format(str_end_file))
                        r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name))
                    else:
                        tentative = 0
                        count += 1
                        r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name))
                        stats.add_app_not_analyzed()
                        dict_analysis_app["app_analyzed"] = False
                        write_json_file_log(md5_app, dict_analysis_app)
                        logger.error("Unable to start emulator, pass to next app")
                        str_end_file = "*" * 20
                        logger.info("{}\n\n".format(str_end_file))
                        shutil.move(app, os.path.join(os.getcwd(), "apps_analyzed"))
                        

            else:
                logger.info("App already analyzed, pass to next app")
                shutil.move(app, os.path.join(os.getcwd(), "apps_analyzed"))
                count += 1

        except MyTimeoutExcpetion as e:
            tentative += 1
            if tentative < MAX_TENTATIVE:
                logger.error("Exception stop emulator, Exception: {}".format(e))
                str_end_file = "*" * 20
                logger.info("{}\n\n".format(str_end_file))
                r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name))
            else:
                tentative = 0
                count += 1
                r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name))
                stats.add_app_not_analyzed()
                logger.error("Exception stop emulator pass to next apps, Exception: {}".format(e))
                dict_analysis_app["app_analyzed"] = False
                write_json_file_log(md5_app, dict_analysis_app)
                str_end_file = "*" * 20
                logger.info("{}\n\n".format(str_end_file))
                shutil.move(app, os.path.join(os.getcwd(), "apps_analyzed"))
                

        except Exception as e:
            tentative += 1
            if tentative < MAX_TENTATIVE:
                logger.error("Exception stop emulator, Exception: {}".format(e))
                str_end_file = "*" * 20
                logger.info("{}\n\n".format(str_end_file))
                r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name))
            else:
                tentative = 0
                count += 1
                r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name))
                stats.add_app_not_analyzed()
                logger.error("Exception stop emulator pass to next apps, Exception: {}".format(e))
                dict_analysis_app["app_analyzed"] = False
                write_json_file_log(md5_app, dict_analysis_app)
                str_end_file = "*" * 20
                logger.info("{}\n\n".format(str_end_file))
                shutil.move(app, os.path.join(os.getcwd(), "apps_analyzed"))
             
    end = time.time()
    logger.info("\n\n")
    logger.info("Execution time: {}, mean: {}".format(end - start, (end - start) / count))
Esempio n. 8
0
from adb import ADB
debug = ADB()

print debug.devices()

debug.shell("input keyevent 26")
debug.shell("input keyevent 82")
debug.shell("input swipe 50 50 800 50")

#debug.screenShot("./ss.png")
Esempio n. 9
0
class Device(object):
    def __init__(self, device=None):
        self.logger = logging.getLogger(self.__class__.__name__)
        if device is None:
            from .DeviceHelper import get_available_devices
            all_devices = get_available_devices()
            if len(all_devices) == 0:
                self.logger.warning("ERROR: No device connected.")
                sys.exit(-1)
            device = all_devices[0]
        if "emulator" in device:
            self.is_emulator = True
        else:
            self.is_emulator = False
        self.device = device

        self.grant_perm = False  ## Grant all permissions while installing. Useful for Android 6.0+

        # basic device information
        self.display_info = None
        self.sdk_version = None
        self.release_version = None
        self.ro_debuggable = None
        self.ro_secure = None
        self.connected = True

        # adapters
        self.adb = ADB(device=self)

        self.adapters = {
            self.adb: True,
            # self.telnet: False,
        }

    def set_up(self):
        """
         Set connections on this device
         """
        # wait for emulator to start
        self.wait_for_device()
        for adapter in self.adapters:
            adapter_enabled = self.adapters[adapter]
            if not adapter_enabled:
                continue
            adapter.set_up()

    def connect(self):
        """
             establish connections on this device
             :return:
             """
        for adapter in self.adapters:
            adapter_enabled = self.adapters[adapter]
            if not adapter_enabled:
                continue
            adapter.connect()

        self.get_sdk_version()
        self.get_release_version()
        self.get_ro_secure()
        self.get_ro_debuggable()
        self.get_display_info()

        self.unlock()
        self.check_connectivity()
        self.connected = True

    def disconnect(self):
        """
       disconnect current device
       :return:
       """
        self.connected = False
        for adapter in self.adapters:
            adapter_enabled = self.adapters[adapter]
            if not adapter_enabled:
                continue
            adapter.disconnect()

    def tear_down(self):
        for adapter in self.adapters:
            adapter_enabled = self.adapters[adapter]
            if not adapter_enabled:
                continue
            adapter.tear_down()

    def install_app(self, app):
        """
        install an app to device
        @param app: instance of App
        @return:
        """
        assert isinstance(app, App)
        # subprocess.check_call(["adb", "-s", self.serial, "uninstall", app.get_package_name()],
        #                       stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        package_name = app.get_package_name()
        if package_name not in self.adb.get_installed_apps():
            install_cmd = ["adb", "-s", self.device, "install", "-r"]
            if self.grant_perm and self.get_sdk_version() >= 23:
                install_cmd.append("-g")
            install_cmd.append(app.app_path)
            install_p = subprocess.Popen(install_cmd, stdout=subprocess.PIPE)
            count = 0
            while self.connected and package_name not in self.adb.get_installed_apps(
            ):
                print("Please wait while installing the app...")
                count += 1
                if count > 30:
                    break
                time.sleep(2)
            if not self.connected:
                install_p.terminate()
                return
            install_p.terminate()
        # dumpsys_p = subprocess.Popen(["adb", "-s", self.serial, "shell",
        #                               "dumpsys", "package", package_name], stdout=subprocess.PIPE)
        # dumpsys_lines = []
        # while True:
        #     line = dumpsys_p.stdout.readline()
        #     if not line:
        #         break
        #     if not isinstance(line, str):
        #         line = line.decode()
        #     dumpsys_lines.append(line)
        # if self.output_dir is not None:
        #     package_info_file_name = "%s/dumpsys_package_%s.txt" % (self.output_dir, app.get_package_name())
        #     package_info_file = open(package_info_file_name, "w")
        #     package_info_file.writelines(dumpsys_lines)
        #     package_info_file.close()
        # app.dumpsys_main_activity = self.__parse_main_activity_from_dumpsys_lines(dumpsys_lines)

        self.logger.info("App installed: %s" % package_name)
        self.logger.info("Main activity: %s" % app.get_main_activity())

    def uninstall_app(self, app):
        """
        Uninstall an app from device.
        :param app: an instance of App or a package name
        """
        if isinstance(app, App):
            package_name = app.get_package_name()
        else:
            package_name = app
        if package_name in self.adb.get_installed_apps():
            uninstall_cmd = [
                "adb", "-s", self.device, "uninstall", package_name
            ]
            uninstall_p = subprocess.Popen(uninstall_cmd,
                                           stdout=subprocess.PIPE)
            while package_name in self.adb.get_installed_apps():
                print("Please wait while uninstalling the app...")
                time.sleep(2)
            uninstall_p.terminate()

    def start_app(self, app):
        """
       start an app on the device
       :param app: instance of App, or str of package name
       :return:
       """
        if isinstance(app, str):
            package_name = app
        elif isinstance(app, App):
            package_name = app.get_package_name()
            if app.get_main_activity():
                package_name += "/%s" % app.get_main_activity()
        else:
            self.logger.warning("unsupported param " + app + " with type: ",
                                type(app))
            return
        intent = Intent(suffix=package_name)
        self.send_intent(intent)

    def pull_file(self, remote_file, local_file):
        self.adb.run_cmd(["pull", remote_file, local_file])

    def push_file(self, local_file, remote_dir="/sdcard/"):
        """
       push file/directory to target_dir
       :param local_file: path to file/directory in host machine
       :param remote_dir: path to target directory in device
       :return:
       """
        if not os.path.exists(local_file):
            self.logger.warning("push_file file does not exist: %s" %
                                local_file)
        self.adb.run_cmd(["push", local_file, remote_dir])

    def shutdown(self):
        self.adb.shell("reboot -p")

    def wait_for_device(self):
        """
        wait until the device is fully booted
        :return:
        """
        self.logger.info("waiting for device")
        try:
            subprocess.check_call(
                ["adb", "-s", self.device, "wait-for-device"])
        except:
            self.logger.warning("error waiting for device")

    def get_sdk_version(self):
        """
        Get version of current SDK
        """
        if self.sdk_version is None:
            self.sdk_version = self.adb.get_sdk_version()
        return self.sdk_version

    def get_release_version(self):
        """
        Get version of current SDK
        """
        if self.release_version is None:
            self.release_version = self.adb.get_release_version()
        return self.release_version

    def get_ro_secure(self):
        if self.ro_secure is None:
            self.ro_secure = self.adb.get_ro_secure()
        return self.ro_secure

    def get_ro_debuggable(self):
        if self.ro_debuggable is None:
            self.ro_debuggable = self.adb.get_ro_debuggable()
        return self.ro_debuggable

    def get_display_info(self, refresh=True):
        """
        get device display information, including width, height, and density
        :param refresh: if set to True, refresh the display info instead of using the old values
        :return: dict, display_info
        """
        if self.display_info is None or refresh:
            self.display_info = self.adb.get_display_info()
        return self.display_info

    def unlock(self):
        """
        unlock screen
        skip first-use tutorials
        etc
        :return:
        """
        self.adb.unlock()

    def check_connectivity(self):
        """
        check if the device is available
        """
        for adapter in self.adapters:
            adapter_name = adapter.__class__.__name__
            adapter_enabled = self.adapters[adapter]
            if not adapter_enabled:
                print("[CONNECTION] %s is not enabled." % adapter_name)
            else:
                if adapter.check_connectivity():
                    print("[CONNECTION] %s is enabled and connected." %
                          adapter_name)
                else:
                    print("[CONNECTION] %s is enabled but not connected." %
                          adapter_name)

    def send_intent(self, intent):
        """
        send an intent to device via am (ActivityManager)
        :param intent: instance of Intent or str
        :return:
        """
        assert self.adb is not None
        assert intent is not None
        if isinstance(intent, Intent):
            cmd = intent.get_cmd()
        else:
            cmd = intent
        return self.adb.shell(cmd)

    def start_activity_via_monkey(self, package):
        """
        use monkey to start activity
        @param package: package name of target activity
        """
        cmd = 'monkey'
        if package:
            cmd += ' -p %s' % package
        out = self.adb.shell(cmd)
        if re.search(r"(Error)|(Cannot find 'App')", out,
                     re.IGNORECASE | re.MULTILINE):
            raise RuntimeError(out)

    def get_package_path(self, package_name):
        """
        get installation path of a package (app)
        :param package_name:
        :return: package path of app in device
        """
        dat = self.adb.shell('pm path %s' % package_name)
        package_path_re = re.compile('^package:(.+)$')
        m = package_path_re.match(dat)
        if m:
            path = m.group(1)
            return path.strip()
        return None

    def app_is_running(self, packageName):
        """
        Get app's pid information
         USER      PID   PPID  VSIZE  RSS   WCHAN              PC  NAME
         u0_a1104  10881 870   1646504 57404 SyS_epoll_ 0000000000 S com.phikal.regex
        :return:
        """
        cmd = "adb -s " + self.device + " shell \"ps|grep " + packageName + "\""
        proc = subprocess.Popen(cmd,
                                shell=True,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.STDOUT)
        (stdout, stderr) = proc.communicate()
        vtLine = stdout.split(os.linesep)
        if len(vtLine) > 1:
            for line in vtLine:
                vtLine = line.strip().split()
                if len(vtLine) == 9 and vtLine[8] == packageName:
                    return True
        proc.terminate()
        return False

    def get_top_activity_name(self):
        """
        Get current activity
        """
        r = self.adb.shell("dumpsys activity activities")
        activity_line_re = re.compile(
            '\* Hist #\d+: ActivityRecord{[^ ]+ [^ ]+ ([^ ]+) t(\d+)}')
        m = activity_line_re.search(r)
        if m:
            return m.group(1).split('/')[0]
            # return m.group(1).replace("/","")
        # data = self.adb.shell("dumpsys activity top").splitlines()
        # regex = re.compile("\s*ACTIVITY ([A-Za-z0-9_.]+)/([A-Za-z0-9_.]+)")
        # m = regex.search(data[1])
        # if m:
        #     return m.group(1) + "/" + m.group(2)
        self.logger.warning("Unable to get top activity name.")
        return None

    @staticmethod
    def __parse_main_activity_from_dumpsys_lines(lines):
        main_activity = None
        activity_line_re = re.compile("[^ ]+ ([^ ]+)/([^ ]+) filter [^ ]+")
        action_re = re.compile("Action: \"([^ ]+)\"")
        category_re = re.compile("Category: \"([^ ]+)\"")

        activities = {}

        cur_package = None
        cur_activity = None
        cur_actions = []
        cur_categories = []

        for line in lines:
            line = line.strip()
            m = activity_line_re.match(line)
            if m:
                activities[cur_activity] = {
                    "actions": cur_actions,
                    "categories": cur_categories
                }
                cur_package = m.group(1)
                cur_activity = m.group(2)
                if cur_activity.startswith("."):
                    cur_activity = cur_package + cur_activity
                cur_actions = []
                cur_categories = []
            else:
                m1 = action_re.match(line)
                if m1:
                    cur_actions.append(m1.group(1))
                else:
                    m2 = category_re.match(line)
                    if m2:
                        cur_categories.append(m2.group(1))

        if cur_activity is not None:
            activities[cur_activity] = {
                "actions": cur_actions,
                "categories": cur_categories
            }

        for activity in activities:
            if "android.intent.action.MAIN" in activities[activity]["actions"] \
                    and "android.intent.category.LAUNCHER" in activities[activity]["categories"]:
                main_activity = activity
        return main_activity