android模拟器_android模拟器配置 - CSDN
  • 强大好用高性能的 Android 模拟器 (在电脑流畅运行APK安卓软件游戏的利器) Genymotion 是一款优秀专业高性能的安卓 Android 模拟器!它支持 Windows、Mac、Linux,由于其模拟运行速度很快画面流畅
  • Android Studio 模拟器的选择和安装

    万次阅读 2017-11-05 20:55:57
    Android Studio 模拟器的选择和安装 一、Android Studio 的 AVD 设置 Android Studio 程序可以在真机上调试运行,Android Studio 也提供了模拟器来调试运行,这时需要配置 AVD 来选择你调试程序的模拟环境。 ...

    一、Android Studio 自带的AVD模拟器

    Android Studio 程序可以在真机上调试运行,Android Studio 也提供了模拟器来调试运行,这时需要配置 AVD 来选择你调试程序的模拟环境。
    1. 在 Intel CPU 的主机上启用 HAXM
    在 Intel CPU 的主机上,为了加速AVD模拟器的运行速度,需要启用 HAXM 。如果在没有启用 HAXM 时就运行程序,调用AVD模拟器时会报如下错误:

    emulator: ERROR: x86 emulation currently requires hardware acceleration!
    Please ensure Intel HAXM is properly installed and usable.
    CPU acceleration status: HAX kernel module is not installed!

    出现此警告的原因是AVD模拟器调用X86架构的安卓虚拟机需要使用到Intel HAXM 引擎,而本机尚未进行安装导致。
    此时,应该先进入 BIOS 启用 Virtualization Technology 选项。然后从 https://software.intel.com/en-us/android/articles/intel-hardware-accelerated-execution-manager/ 下载,也可以直接在 Android Studio 的 SDK 中下载,再安装即可。


    2. 对于非 Intel CPU 的主机
    对于非 Intel CPU 的主机或不能安装 HAXM 的主机(像我的云主机),则只能选择 arm 模拟器 或 选择其它第三方的模拟器 (像Genymotion)。
    arm 模拟器的设置如下,不过一般情况下, arm 模拟器速度很慢 (像我的云主机启动它需要个吧小时),所以,应该尽量选用Genymotion等虚拟机。

    3. 设置
    如果以上配置无误,就可以运行程序试试。如果出现类似如下面的警告:
    emulator: WARNING: Requested RAM size of 1536MB is too large for your environment, and is reduced to 1152MB.
    emulator: device fd:596
    HAXM is not working and emulator runs in emulation mode
    emulator: The memory needed by this AVD exceeds the max specified in your HAXM configuration.
    emulator: AVD RAM size = 1152 MB
    emulator: HAXM max RAM size = 1024 MB
    emulator: You might want to adjust your AVD RAM size and/or HAXM configuration to run in fast virt mode.
    Cannot set up guest memory ‘pc.ram’: Invalid argument
    警告提示模拟器RAM过大,需要在 AVD 中将模拟器的RAM改为512~1024,这样模拟器才能正常启动。

     

    二、android studio外挂Genymotion模拟器

    Genymotion虚拟机可以模拟Galaxy、SAMSUNG、SONY、HTC等主流手机,运行速度快,是现在广受欢迎的虚拟机。Genymotion依赖 VirtualBox 加载手机虚拟机。
    1. 安装 VirtualBox
    https://www.virtualbox.org/wiki/Downloads
    下载 VirtualBox ,再安装,过程从略。
    2. 安装 Genymotion
    https://www.genymotion.com/download/ 下载 Genymotion ,下载是要用邮箱注册账号后才能下载。
    官网提供了两个版本,带有VirtualBox的Genymotion整合包和不带VirtualBox的Genymotion安装包,可以根据需要下载相应版本安装。安装过程从略。
    3. 下载 .ova 虚拟设备
    启动 Genymotion,添加对应手机的 Virtual device ,如下图。


    不过如果因为墙的阻挡,也许会下载出错。如果Genymotion添加 Virtual device 时出现如下的错误:

    Failed to deploy virtual device.
    Unable to create virtual device:
    Connection timeout occurred.

    那就只好手工下载 Virtual device 的离线.ova文件了。
    方法一:下载官方离线.ova文件
    即使刚才下载失败了,但是它已经在 “C:\Users\用户主目录\AppData\Local\Genymobile\genymotion.log” 文件里保留了官方.ova文件的地址,打开该文件,找到类似 “http://files2.genymotion.com/dists/6.0.0/ova/genymotion_vbox86p_6.0_160114_090449.ova” 的路径,即您想要下载的.ova镜像文件URL;复制到浏览器或用第三方下载工具下载该文件。
    方法二:贴吧下载
    有些网友下载了一些.ova文件,大家可以在网上搜搜,也可以到百度贴吧里找找。像下面的地址里就有一些:
    链接: http://pan.baidu.com/s/1jHfuJNg 密码: 222g
    4. 安装下载的.ova 离线文件
    下载好后拷贝到 “C:\Users\用户主目录\AppData\Local\Genymobile\Genymotion\ova” 文件夹下。
    然后打开 VirtualBox -> 管理 -> 导入虚拟电脑 (快捷键:Ctrl+I ) -> 选择下载好的 .ova 文件 -> 下一步 -> 导入 。导入完成之后就OK了。这时候打开Genymotion就看到可以使用了。
    5. 将Genymotion加入 Android Studio
    如下图,在 Android Studio 的 Setting 中加入 Genymotion 的插件即可。




    6. 运行 Genymotion
    现在可以点击 Android Studio 上的 Genymotion 图标来运行虚拟机,如果此时出现如下错误说明需要重装或升级显卡驱动。
    make sure that your video card supports OpenGL 2.0 and update the drivers.

    五、运行
    正常运行后,可以通过虚拟机的
    Settings -> Language & input -> Language -> 中文(简体) 将虚拟手机中文化。


    然后,可以在虚拟机里调试程序了。


     

    三、真机模拟器

    对于我这刚入门的菜鸟来说,我在配置Android的开发环境中,遇到的问题实在是太多了,都快花费我一个星期的时间了,在这期间出了翻墙下载SDK之外,其他的世间都在搞Android virtual device出现的问题,由于本人的能力有限以及电脑配置的不给力,Android virtual device中出现的问题始终都没有得到解决,后来看了网上很多人都在说使用Google自带的Android virtual device来进行调试运行时会比较慢,性能也不是很好,然后使用真机模拟的话速度是比较快的,效果也不错。那么接下来我要讲的就是如何在Android studio中使用真机进行调试以及在这过程中遇到的一个问题


    首先,你要先创建好一个项目




    接着在工具栏中找到APP这个按钮,选择Edit Configurations




    在弹出的对话框中,找到“ Deployment Target Options” 并选择“ USB Device ”,然后点击确定



    以上配置完之后,我们就可以进行调试了,在工具栏中找到绿色的三角符号按钮(或者按快捷键Shift+F10)运行项目



    启动run后,软件开始生成apk安装包,并自动安装到手机上,第一次执行的话会慢一些,往后就快了。然后我们识别出来的设备可以再Android Monitor这一栏中看到



    安卓手机也自动安装好app并自动执行





    在以上的操作过程中,出现了一个问题,在Android Monitor这栏中,没有识别出我们的手机设备,显示No Connected Devices



    出现以上的原因是电脑中的驱动没有安装好,Android studio不能识别出我们的设备,然而解决方法很简单,我们只需要这我们的电脑中安装一个豌豆荚就可以了,这个应用可以帮我们直接搞定设备驱动安装的问题。



    真机调试参考自:http://jingyan.baidu.com/article/fea4511a75d627f7ba912540.html


    展开全文
  • 最新强大android模拟器

    2020-07-30 23:32:33
    强大android 模拟器,一键安装,方便,好用,效率比以前模拟器好N倍。
  • Android 模拟器AVD下载与使用

    万次阅读 2018-05-23 09:52:56
    AVD的全称为:Android Virtual Device,是Android的虚拟设备(模拟器),使用模拟器进行调试,不用实时连到物理设备上测试,方便调试。可以通过命令行创建和启动AVD,也可以运行AVD Manager.exe来创建和启动AVD。1...

    AVD的全称为:Android Virtual Device,是Android的虚拟设备(模拟器),使用模拟器进行调试,不用实时连到物理设备上测试,方便调试。

    可以通过命令行创建和启动AVD,也可以运行AVD Manager.exe来创建和启动AVD。

    1环境准备

    1.1JDK安装与环境配置

        JDK(JavaDevelopment Kit) 是 Java 语言的软件开发工具包。因为Android应用是使用Java语言进行开发的,而Java的核心就是JDK,所以我们需要先安装JDK。

    1.        官网下载:http://www.oracle.com/technetwork/java/javase/downloads/index.html

    Ø  点击上图指示的两个位置,跳转到如下界面,根据你的电脑系统选择对应的版本下载,在选择版本和下载之前需要先接收协议

    2.   或者到http://jdk.android-studio.org/下载,可以下载以前的版本

    3.   下载完成后,选择路径安装,注:不可以保存在中文路径下。

    4.   安装完成后,进行环境配置;右键我的电脑—>属性—>高级系统设置—>环境变量

    5.   系统变量—>新建,变量名:JAVA_HOME(代表JDK安装路径),变量值:JDK的安装路径

    6.   系统变量—>新建,变量名:CLASSPATH,变量值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar

    7.   系统变量—>path—>点击编辑,变量值添加:;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;

    8.   命令行输入 java -version,出现如下结果即代表安装成功

    1.2Android SDK下载与配置

    AndroidSDK指得是Android专属的软件开发工具包,是用于为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件的开发工具的集合。

    1.   官网下载(需翻墙):http://developer.android.com/sdk/index.html

    2.   其他下载地址:http://www.androiddevtools.cn/

    先找到SDK Tools,下载zip格式的,解压至目标路径位置即可;下载exe格式的,需双击安装

    http://tools.android-studio.org/index.php/sdk

    3.  解压或安装完成的目录如下图,AVDmanager.exe是管理安卓虚拟机的程序,可以直接双击运行,然后创建模拟器;SDK manager.exe是用来管理sdk相关的工具、API等的

    4.   双击运行SDK manager.exe,Android SDK Manage负责下载或更新不同版本的SDK包,默认安装的Android SDK Manager只安装了一个版本的sdk tools。

    5.   打开Android SDK Manager,会自动获取可安装的sdk版本,但是未翻墙的情况下,有时候会出现获取失败的情况。

    6.   获取失败的情况下,需要设置代理:

    Ø  点击“Tools”>“Options...”

    Ø  settings窗体中“HTTP Proxy Server”输入mirrors.neusoft.edu.cnHTTP;Proxy Port输入80,勾选Other中“Force https..”开头选项

    7.   根据需要,选择工具;个工具的作用如下:

       Tools目录(必须的工具):

    Ø Android SDKTools(必须,只需下载一个版本,一般选最新版本):基础工具包,版本号带rc字样的是预览版。

    Ø Android SDKPlatform-tools(必须,只需下载一个版本,一般选最新版本):从android2.3开始划出此目录,存放公用开发工具,比如adb、sqlite3等,被划分到了这里。

    Ø Android SDKBuild-tools(必须,可以安装多个版本):Android项目构建工具

       Android xxx(API xx)目录(可选的各平台开发工具): 

    Ø Documentationfor Android Sdk(可选):安卓开发者官网的一些离线文档,不过下载下来打开也很慢。

    Ø SDKPlatform(必须):对应平台的开发工具,需要在哪个版本的平台下开发就下载哪个。

    Ø Samples forSDK(可选,此项在高版本tools中已不提供,需要在IDE里通过Import Sample引入,当然也可以下载离线版):内置的安卓示例程序,推荐安装。

    Ø Sources forAndroid SDK(可选):安卓API的源代码,推荐安装。

    Ø xxxxxxxx  Image(可选):各个以Image结尾的东西是支持相应平台的模拟器。

       Extras目录(可选的扩展):

    Ø AndroidSupport Libraries(需要,高版本tools中已不见了,应该是集成到了别的地方):在低版本平台实现高版本平台控件效果时提供支持。

    Ø AndroidSupport Repository(需要):主要是方便在gradle中使用Android Support Libraries,因为Google并没有把这些库发布到maven center或者jcenter去,而是使用了Google自己的maven仓库。

    Ø Intel x86Emulator Accelerator(HAXM installer)(可选,但非常需要,需要CPU支持虚拟化技术支持):windows平台的Intel x86模拟器加速工具,配合Intel x86 atom/atom_64System Image使用可加快模拟器的运行速度。

    8.   选择完成后,点击安装

    9.   选择Accept License后,点击安装

    10.  开始下载

    11.  下载完成

    12.  Intel x86 Emulator Accelerator(HAXM installer)相关配置

    Ø  开机按F2或delete键进入BIOS-CPU设置里,将Intel 虚拟化技术开启

    Ø  如在Android SDK Manage出现如下显示,无法直接安装Intel x86 Emulator Accelerator(HAXM installer)


    Ø 到官网下载安装包进行安装https://software.intel.com/en-us/articles/intel-hardware-accelerated-execution-manager-intel-haxm

    13.  安装完成后,进行环境配置;右键我的电脑—>属性—>高级系统设置—>环境变量

    14.  系统变量—>新建,变量名:ANDROID_HOME,变量值:SDK的安装路径

    15.  系统变量—>path—>点击编辑,变量值添加:;%ANDROID_HOME%\build-tools\25.0.3;%ANDROID_HOME%\platform-tools;%ANDROID_HOME%\tools;

    2通过命令行

    2.1创建AVD

    Ø  选项:

    -t --target 新的AVD Target ID(必须)

    -c --sdcard 指向一个共享的SD 存储卡的路径或是为新的AVD 定制的新SD 存储卡的容量大小

    -p --path AVD 将被创建的位置路径

    -n --name AVD 的名称(必须)

    -f --force 强制创建(覆盖已存在的AVD)

    -s --skin AVD 的皮肤

    1.   因为前面已经把SDK的路径加到环境变量中,所以可以直接打开命令窗口,执行相关的命令;不然就需要将Android SDK安装目录下的tools子目录(如:D:\Android\android-sdk\tools)加到环境变量中;或直接在该子目录下按shift+右键,选择在此处打开命令窗口。

    2.   例:创建一个名叫GPhone 的AVD,Target ID=2、SD 存储卡容量52M、路径C:\AVD\、皮肤QVGA的AVD,命令为:android create avd -n GPhone -t 2 -c52M -p C:\AVD\ -s QVGA

    3.   系统会输出如下信息来询问是否继续自定义avd设备默认选项是"no",如果输入 "y",接下来可以一步步根据提示,定制自己得模拟器性能参数。

    4.   回车后,创建成功;显示如下

    5.   可以通过android list avd命令查看AVD设备的信息

    2.2启动AVD

    Ø  启动avd命令:emulator -avd AVD名

    Ø  AVD启动成功,如下

    2.3其他相关命令

    Ø  android list :列出机器上所有已经安装的Android版本和AVD设备

    Ø  android list avd :列出机器上所有已经安装的AVD设备

    Ø  android list target :列出机器上所有已经安装的Andoid版本

    Ø  android create avd :创建一个avd设备

    Ø  android move avd :移动或重命名一个avd设备

    Ø  android delete avd :删除一个avd设备

    Ø  android update avd :升级一个avd设备使之符合新的sdk环境

    Ø  android create project :创建一个新的Android项目

    Ø  android update project :更新一个已有的Android项目

    Ø  android create test-project :创建一个新的Android测试项目

    Ø  android update test-project :更新一个已有的Android测试项目

    3AVD Manager.exe

    3.1 创建AVD

    1.         在SDK的安装目录,双击打开AVD Manager.exe

    2.         点击Create…

    3.         各参数的含义如下

    4.         根据需要配置参数后,点击OK

    5.         弹出设备信息,点击OK

    6.         创建成功,显示在设置目录中

    3.2 启动AVD

    1.    选择需要启动的AVD,点击start…

    2.    根据需要配置参数,然后点击Launch

    3.    等待启动完成,如下图

    展开全文
  • 检测Android模拟器的方法和代码实现

    千次阅读 2018-09-17 17:59:41
    刚刚看了一些关于Detect Android Emulator的开源项目/文章/论文, 我看的这些其实都是13年14年提出的方法, 方法里大多是检测一些环境属性, 检查一些文件这样, 但实际上检测的思路并不局限于此. 有的是很直接了当去...

    专自:https://bbs.pediy.com/thread-225717.htm

    刚刚看了一些关于Detect Android Emulator的开源项目/文章/论文, 我看的这些其实都是13年14年提出的方法, 方法里大多是检测一些环境属性, 检查一些文件这样, 但实际上检测的思路并不局限于此. 有的是很直接了当去检测qemu, 而其它的方法则是旁敲侧击比如检测adb, 检测ptrace之类的. 思路也很灵活. 最后看到有提出通过利用QEMU这样的模拟CPU与物理CPU之间的实际差异(任务调度差异), 模拟传感器和物理传感器的差异, 缓存的差异等方法来检测. 相比检测环境属性, 检测效果会提升很多.

     

    下面我就列出各个资料中所提出的一些方法/思路/代码供大家交流学习.

    QEMU Properties

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    public class Property {

        public String name;

        public String seek_value;

     

        public Property(String name, String seek_value) {

            this.name = name;

            this.seek_value = seek_value;

        }

    }

    /**

     * 已知属性, 格式为 [属性名, 属性值], 用于判定当前是否为QEMU环境

     */

    private static Property[] known_props = {new Property("init.svc.qemud", null),

            new Property("init.svc.qemu-props", null), new Property("qemu.hw.mainkeys", null),

            new Property("qemu.sf.fake_camera", null), new Property("qemu.sf.lcd_density", null),

            new Property("ro.bootloader""unknown"), new Property("ro.bootmode""unknown"),

            new Property("ro.hardware""goldfish"), new Property("ro.kernel.android.qemud", null),

            new Property("ro.kernel.qemu.gles", null), new Property("ro.kernel.qemu""1"),

            new Property("ro.product.device""generic"), new Property("ro.product.model""sdk"),

            new Property("ro.product.name""sdk"),

            new Property("ro.serialno", null)};

    /**

     * 一个阈值, 因为所谓"已知"的模拟器属性并不完全准确, 有可能出现假阳性结果, 因此保持一定的阈值能让检测效果更好

     */

    private static int MIN_PROPERTIES_THRESHOLD = 0x5;

    /**

     * 尝试通过查询指定的系统属性来检测QEMU环境, 最后跟阈值比较得出检测结果.

     *

     * @param context A {link Context} object for the Android application.

     * @return {@code true} if enough properties where found to exist or {@code false} if not.

     */

    public boolean hasQEmuProps(Context context) {

        int found_props = 0;

     

        for (Property property : known_props) {

            String property_value = Utilities.getProp(context, property.name);

            // See if we expected just a non-null

            if ((property.seek_value == null) && (property_value != null)) {

                found_props++;

            }

            // See if we expected a value to seek

            if ((property.seek_value != null) && (property_value.indexOf(property.seek_value) != -1)) {

                found_props++;

            }

     

        }

     

        if (found_props >= MIN_PROPERTIES_THRESHOLD) {

            return true;

        }

     

        return false;

    }

    这些都是基于一些经验和特征来比对的属性, 这里的属性以及之后的一些文件呀属性啊之类的我就不再多作解释.

    Device ID

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    private static String[] known_device_ids = {"000000000000000"// Default emulator id

            "e21833235b6eef10"// VirusTotal id

            "012345678912345"};

    public static boolean hasKnownDeviceId(Context context) {

        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);

     

        String deviceId = telephonyManager.getDeviceId();

     

        for (String known_deviceId : known_device_ids) {

            if (known_deviceId.equalsIgnoreCase(deviceId)) {

                return true;

            }

     

        }

        return false;

    }

    Default Number

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    private static String[] known_numbers = {

            "15555215554"// 模拟器默认电话号码 + VirusTotal

            "15555215556""15555215558""15555215560""15555215562""15555215564""15555215566",

            "15555215568""15555215570""15555215572""15555215574""15555215576""15555215578",

            "15555215580""15555215582""15555215584",};

    public static boolean hasKnownPhoneNumber(Context context) {

        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);

     

        String phoneNumber = telephonyManager.getLine1Number();

     

        for (String number : known_numbers) {

            if (number.equalsIgnoreCase(phoneNumber)) {

                return true;

            }

     

        }

        return false;

    }

    IMSI

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    private static String[] known_imsi_ids = {"310260000000000" // 默认IMSI编号

    };

    public static boolean hasKnownImsi(Context context) {

        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);

        String imsi = telephonyManager.getSubscriberId();

     

        for (String known_imsi : known_imsi_ids) {

            if (known_imsi.equalsIgnoreCase(imsi)) {

                return true;

            }

        }

        return false;

    }

    Build类

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    public static boolean hasEmulatorBuild(Context context) {

        String BOARD = android.os.Build.BOARD; // The name of the underlying board, like "unknown".

        // This appears to occur often on real hardware... that's sad

        // String BOOTLOADER = android.os.Build.BOOTLOADER; // The system bootloader version number.

        String BRAND = android.os.Build.BRAND; // The brand (e.g., carrier) the software is customized forif any.

        // "generic"

        String DEVICE = android.os.Build.DEVICE; // The name of the industrial design. "generic"

        String HARDWARE = android.os.Build.HARDWARE; // The name of the hardware (from the kernel command line or

        // /proc). "goldfish"

        String MODEL = android.os.Build.MODEL; // The end-user-visible name for the end product. "sdk"

        String PRODUCT = android.os.Build.PRODUCT; // The name of the overall product.

        if ((BOARD.compareTo("unknown"== 0/* || (BOOTLOADER.compareTo("unknown"== 0*/

                || (BRAND.compareTo("generic"== 0) || (DEVICE.compareTo("generic"== 0)

                || (MODEL.compareTo("sdk"== 0) || (PRODUCT.compareTo("sdk"== 0)

                || (HARDWARE.compareTo("goldfish"== 0)) {

            return true;

        }

        return false;

    }

    运营商名

    1

    2

    3

    4

    5

    public static boolean isOperatorNameAndroid(Context paramContext) {

        String szOperatorName = ((TelephonyManager) paramContext.getSystemService(Context.TELEPHONY_SERVICE)).getNetworkOperatorName();

        boolean isAndroid = szOperatorName.equalsIgnoreCase("android");

        return isAndroid;

    }

    QEMU驱动

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    private static String[] known_qemu_drivers = {"goldfish"};

    /**

     * 读取驱动文件, 检查是否包含已知的qemu驱动

     *

     * @return {@code true} if any known drivers where found to exist or {@code false} if not.

     */

    public static boolean hasQEmuDrivers() {

        for (File drivers_file : new File[]{new File("/proc/tty/drivers"), new File("/proc/cpuinfo")}) {

            if (drivers_file.exists() && drivers_file.canRead()) {

                // We don't care to read much past things since info we care about should be inside here

                byte[] data = new byte[1024];

                try {

                    InputStream is = new FileInputStream(drivers_file);

                    is.read(data);

                    is.close();

                } catch (Exception exception) {

                    exception.printStackTrace();

                }

     

                String driver_data = new String(data);

                for (String known_qemu_driver : FindEmulator.known_qemu_drivers) {

                    if (driver_data.indexOf(known_qemu_driver) != -1) {

                        return true;

                    }

                }

            }

        }

     

        return false;

    }

    QEMU文件

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    private static String[] known_files = {"/system/lib/libc_malloc_debug_qemu.so""/sys/qemu_trace",

            "/system/bin/qemu-props"};

    /**

     * 检查是否存在已知的QEMU环境文件

     *

     * @return {@code true} if any files where found to exist or {@code false} if not.

     */

    public static boolean hasQEmuFiles() {

        for (String pipe : known_files) {

            File qemu_file = new File(pipe);

            if (qemu_file.exists()) {

                return true;

            }

        }

     

        return false;

    }

    Genymotion文件

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    private static String[] known_geny_files = {"/dev/socket/genyd""/dev/socket/baseband_genyd"};

    /**

     * 检查是否存在已知的Genemytion环境文件

     *

     * @return {@code true} if any files where found to exist or {@code false} if not.

     */

    public static boolean hasGenyFiles() {

        for (String file : known_geny_files) {

            File geny_file = new File(file);

            if (geny_file.exists()) {

                return true;

            }

        }

     

        return false;

    }

    QEMU管道

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    private static String[] known_pipes = {"/dev/socket/qemud""/dev/qemu_pipe"};

    /**

     * 检查是否存在已知的QEMU使用的管道

     *

     * @return {@code true} if any pipes where found to exist or {@code false} if not.

     */

    public static boolean hasPipes() {

        for (String pipe : known_pipes) {

            File qemu_socket = new File(pipe);

            if (qemu_socket.exists()) {

                return true;

            }

        }

     

        return false;

    }

    设置断点

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    static {

        // This is only valid for arm

        System.loadLibrary("anti");

    }

    public native static int qemuBkpt();

     

    public static boolean checkQemuBreakpoint() {

        boolean hit_breakpoint = false;

     

        // Potentially you may want to see if this is a specific value

        int result = qemuBkpt();

     

        if (result > 0) {

            hit_breakpoint = true;

        }

     

        return hit_breakpoint;

    }

    以下是对应的c++代码

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    void handler_sigtrap(int signo) {

      exit(-1);

    }

     

    void handler_sigbus(int signo) {

      exit(-1);

    }

     

    int setupSigTrap() {

      // BKPT throws SIGTRAP on nexus 5 / oneplus one (and most devices)

      signal(SIGTRAP, handler_sigtrap);

      // BKPT throws SIGBUS on nexus 4

      signal(SIGBUS, handler_sigbus);

    }

     

    // This will cause a SIGSEGV on some QEMU or be properly respected

    int tryBKPT() {

      __asm__ __volatile__ ("bkpt 255");

    }

     

    jint Java_diff_strazzere_anti_emulator_FindEmulator_qemuBkpt(JNIEnv* env, jobject jObject) {

     

      pid_t child = fork();

      int child_status, status = 0;

     

      if(child == 0) {

        setupSigTrap();

        tryBKPT();

      else if(child == -1) {

        status = -1;

      else {

     

        int timeout = 0;

        int = 0;

        while ( waitpid(child, &child_status, WNOHANG) == 0 ) {

          sleep(1);

          // Time could be adjusted here, though in my experience if the child has not returned instantly

          // then something has gone wrong and it is an emulated device

          if(i++ == 1) {

            timeout = 1;

            break;

          }

        }

     

        if(timeout == 1) {

          // Process timed out - likely an emulated device and child is frozen

          status = 1;

        }

     

        if ( WIFEXITED(child_status) ) {

          // 子进程正常退出

          status = 0;

        else {

          // Didn't exit properly - very likely an emulator

          status = 2;

        }

     

        // Ensure child is dead

        kill(child, SIGKILL);

      }

     

      return status;

    }

    这里我的描述可能并不准确, 因为并没有找到相关的资料. 我只能以自己的理解来解释一下:

     

    SIGTRAP是调试器设置断点时发生的信号, 在nexus5或一加手机等大多数手机都可以触发. SIGBUS则是在一个总线错误, 指针也许访问了一个有效地址, 但总线会因为数据未对齐等原因无法使用, 在nexus4手机上可以触发. 而bkpt则是arm的断点指令, 这是曾经qemu被提出来的一个issue, qemu会因为SIGSEGV信号而崩溃, 作者想利用这个崩溃来检测qemu. 如果程序没有正常退出或被冻结, 那么就可以认定很可能是在模拟器里.

    ADB

    1

    2

    3

    4

    5

    6

    7

    8

    public static boolean hasEmulatorAdb() {

        try {

            return FindDebugger.hasAdbInEmulator();

        } catch (Exception exception) {

            exception.printStackTrace();

            return false;

        }

    }

    isUserAMonkey()

    1

    2

    3

    public static boolean isUserAMonkey() {

        return ActivityManager.isUserAMonkey();

    }

    这个其实是用于检测当前操作到底是用户还是脚本在要求应用执行.

    isDebuggerConnected()

    1

    2

    3

    4

    5

    6

    /**

     * 你信或不信, 还真有许多加固程序使用这个方法...

     */

    public static boolean isBeingDebugged() {

        return Debug.isDebuggerConnected();

    }

    这个方法是用来检测调试, 判断是否有调试器连接.

    ptrace

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    private static String tracerpid = "TracerPid";

    /**

     * 阿里巴巴用于检测是否在跟踪应用进程

     *

     * 容易规避, 用法是创建一个线程每3秒检测一次, 如果检测到则程序崩溃

     *

     * @return

     * @throws IOException

     */

    public static boolean hasTracerPid() throws IOException {

        BufferedReader reader = null;

        try {

            reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/self/status")), 1000);

            String line;

     

            while ((line = reader.readLine()) != null) {

                if (line.length() > tracerpid.length()) {

                    if (line.substring(0, tracerpid.length()).equalsIgnoreCase(tracerpid)) {

                        if (Integer.decode(line.substring(tracerpid.length() + 1).trim()) > 0) {

                            return true;

                        }

                        break;

                    }

                }

            }

     

        } catch (Exception exception) {

            exception.printStackTrace();

        finally {

            reader.close();

        }

        return false;

    }

    这个方法是通过检查/proc/self/statusTracerPid项, 这个项在没有跟踪的时候默认为0, 当有程序在跟踪时会修改为对应的pid. 因此如果TracerPid不等于0, 那么就可以认为是在模拟器环境.

    TCP连接

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    public static boolean hasAdbInEmulator() throws IOException {

        boolean adbInEmulator = false;

        BufferedReader reader = null;

        try {

            reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/net/tcp")), 1000);

            String line;

            // Skip column names

            reader.readLine();

     

            ArrayList<tcp> tcpList = new ArrayList<tcp>();

     

            while ((line = reader.readLine()) != null) {

                tcpList.add(tcp.create(line.split("\\W+")));

            }

     

            reader.close();

     

            // Adb is always bounce to 0.0.0.0 - though the port can change

            // real devices should be != 127.0.0.1

            int adbPort = -1;

            for (tcp tcpItem : tcpList) {

                if (tcpItem.localIp == 0) {

                    adbPort = tcpItem.localPort;

                    break;

                }

            }

     

            if (adbPort != -1) {

                for (tcp tcpItem : tcpList) {

                    if ((tcpItem.localIp != 0) && (tcpItem.localPort == adbPort)) {

                        adbInEmulator = true;

                    }

                }

            }

        } catch (Exception exception) {

            exception.printStackTrace();

        finally {

            reader.close();

        }

     

        return adbInEmulator;

    }

     

    public static class tcp {

     

        public int id;

        public long localIp;

        public int localPort;

        public int remoteIp;

        public int remotePort;

     

        static tcp create(String[] params) {

            return new tcp(params[1], params[2], params[3], params[4], params[5], params[6], params[7], params[8],

                            params[9], params[10], params[11], params[12], params[13], params[14]);

        }

     

        public tcp(String id, String localIp, String localPort, String remoteIp, String remotePort, String state,

                        String tx_queue, String rx_queue, String tr, String tm_when, String retrnsmt, String uid,

                        String timeout, String inode) {

            this.id = Integer.parseInt(id16);

            this.localIp = Long.parseLong(localIp, 16);

            this.localPort = Integer.parseInt(localPort, 16);

        }

    }

    这个方法是通过读取/proc/net/tcp的信息来判断是否存在adb. 比如真机的的信息为0: 4604D20A:B512 A3D13AD8..., 而模拟器上的对应信息就是0: 00000000:0016 00000000:0000, 因为adb通常是反射到0.0.0.0这个ip上, 虽然端口有可能改变, 但确实是可行的.

    TaintDroid

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    public static boolean hasPackageNameInstalled(Context context, String packageName) {

        PackageManager packageManager = context.getPackageManager();

     

        // In theory, if the package installer does not throw an exception, package exists

        try {

            packageManager.getInstallerPackageName(packageName);

            return true;

        } catch (IllegalArgumentException exception) {

            return false;

        }

    }

    public static boolean hasAppAnalysisPackage(Context context) {

        return Utilities.hasPackageNameInstalled(context, "org.appanalysis");

    }

    public static boolean hasTaintClass() {

        try {

            Class.forName("dalvik.system.Taint");

            return true;

        }

        catch (ClassNotFoundException exception) {

            return false;

        }

    }

    这个比较单纯了. 就是通过检测包名, 检测Taint类来判断是否安装有TaintDroid这个污点分析工具. 另外也还可以检测TaintDroid的一些成员变量.

    eth0

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    private static boolean hasEth0Interface() {

        try {

            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {

                NetworkInterface intf = en.nextElement();

                if (intf.getName().equals("eth0"))

                    return true;

            }

        } catch (SocketException ex) {

        }

        return false;

    }

    检测是否存在eth0网卡.

    传感器

    手机上配备了各式各样的传感器, 但它们实质上都是基于从环境收集的信息输出值, 因此想要模拟传感器是非常具有挑战性的. 这些传感器为识别手机和模拟器提供了新的机会.

     

    比如在论文Rage Against the Virtual Machine: Hindering Dynamic Analysis of Android Malware中, 作者对Android模拟器的加速器进行测试, 作者发现Android模拟器上的传感器会在相同的时间间隔内(观测结果是0.8s, 标准偏差为0.003043)产生相同的值. 显然对于现实世界的传感器, 这是不可能的.

     

    acc-cdf.png

     

    于是我们可以先注册一个传感器监听器, 如果注册失败, 就可能是在模拟器中(排除实际设备不支持传感器的可能性). 如果注册成功, 那么检查onSensorChanged回调方法, 如果在连续调用这个方法的过程所观察到的传感器值或时间间隔相同, 那么就可以认定是在模拟器环境中.

    QEMU任务调度

    出于性能优化的原因, QEMU在每次执行指令时都不会主动更新程序计数器(PC), 由于翻译指令在本地执行, 而增加PC需要额外的指令带来开销. 所以QEMU只在执行那些从线性执行过程里中断的指令(例如分支指令)时才会更新程序计数器. 这也就导致在执行一些基本块的期间如果发生了调度事件, 那么也没有办法恢复调度前的PC, 也是出于这个原因, QEMU仅在执行基本块后才发生调度事件, 绝不会执行的过程中发生.

     

    sche-point.png

     

    如上图, 因为调度可能在任意时间发生, 所以在非模拟器环境下, 会观察到大量的调度点. 而在模拟器环境中, 只能看到特定的调度点.

    SMC识别

    因为QEMU会跟踪代码页的改动, 于是存在一种新颖的方法来检测QEMU--使用自修改代码(Self-Modifying Code, SMC)引起模拟器和实际设备之间的执行流变化.

     

    memory.png

     

    ARM处理器包含有两个不同的缓冲Cache, 一个用于指令访问(I-Cache), 而另一个用于数据访问(D-Cache). 但如ARM这样的哈佛架构并不能保证I-Cache和D-Cache之间的一致性. 因此CPU有可能在新代码片已经写入主存后执行旧的代码片(也许是无效的).

     

    这个问题可以通过强迫两个缓存一致得到解决, 这有两步:

    1. 清理主存, 以便将D-Cache中新写入的代码移入主存
    2. 使I-Cache无效, 以便它可以用主存的新内容重新填充.

    在原生Android代码中, 可以使用cacheflush函数, 该函数通过系统调用完成上述操作.

     

    diff.png

     

    识别代码, 使用一个具有读写权限的内存, 其中包含两个不同函数f1和f2的代码, 这两个函数其实很简单, 只是单纯在一个全局字符串变量的末尾附加各自的函数名称, 这两个函数会在循环里交错执行, 这样就可以通过结果的字符串推断出函数调用序列.

     

    如前所述, 我们调用cacheflush来同步缓存. 在实际设备和模拟器上运行代码得到的结果是相同的--每次执行都会产生一致的函数调用序列.

     

    接下来我们移除调用cacheflush, 执行相同的操作. 那么在实际设备中, 我们每次运行都会观察到一个随机的函数调用序列, 这也如前所述的那样, 因为I-Cache可能包含一些旧指令, 每次调用的时候缓存都不同步所导致的.

     

    而模拟器环境却不会发生这样的情况, 而且函数调用序列会跟之前没有移除cacheflush时完全相同, 也就是每次函数调用前缓存都是一致的. 这是因为QEMU会跟踪代码页上的修改, 并确保生成的代码始终与内存中的目标指令匹配, 因此QEMU会放弃之前版本的代码翻译并重新生成新代码.

    结语

    看到这里会不会已经觉得检测方法够多了. 可是我还只是看了13年14年的资料. 有关近几年的资料还未涉及.

     

    最后我就把这些检测方法整合在一张思维导图(见附件)里供大家一览, 欢迎大家和我交流带带我

    参考链接


     

    快讯:[看雪招聘]十八年来,看雪平台输出了大量安全人才,影响三代安全人才!

    展开全文
  • Android模拟器Root

    千次阅读 2018-09-21 17:18:49
    Android模拟器Root前言需要的准备的资料操作步骤一、进入Android SDK的安装目录二、以可写方式启动模拟器三、安装Supersu.apk四、向系统添加su文件五、修改su文件权限六、安装su二进制文件,设置后台守护程序七、...

    前言

    安卓开发,免不了要用到root权限查看data/data/com.xxx.xxx/里的文件内容进行操作,虽然android的内核是linux系统,但是在的android中并没有提供su文件,所以无法进行linux下的sudo命令。我们需要向root的系统中添加su文件,同时改变su的权限。

    需要的准备的资料

    1. supersu.apk 手机root后进行授权管理的软件
    2. supersu.zip 包括su二进制文件等
      下载地址http://www.supersu.com/download,页面中分为APK和ZIP两个部分,分别对应上面的两个文件,如果不想使用GooglePlay下载apk,可以下载History里的最后一版。本文用的版本为SuperSU V2.79 ,Recovery V2.79 Flashable.zip
      本文所有操作均在Mac OS下执行。

    操作步骤

    一、进入Android SDK的安装目录

    Android SDK在我的电脑上目录为:/Users/[系统用户名]/Library/Android/
    打开terminal进入到安装目录的tools目录

    $ cd /Users/[系统用户名]/Library/Android/sdk/tools/
    

    为什么要进到这个目录呢?因为下一步要用到的emulator命令在这个目录里,这样方便操作。

    二、以可写方式启动模拟器

    $ emulator -avd Pixel_XL_API_26 -writable-system
    

    注:Pixel_XL_API_26为模拟器名称,可以先执行$ emulator -list-avds命令获取所有模拟器名称列表。
    这时候会显示
    emulator: WARNING: System image is writable
    说明启动可写方式成功,但此时terminal处于等待状态,无法再进行操作,如果关闭当前terminal,打开的模拟器也会随之关闭。所以需要再重新打开一个terminal进行后续操作。

    三、安装Supersu.apk

    进入到刚刚下载的supersu.apk的目录,然后执行如下命令

    $ adb -e install SuperSU-v2.79-20161205182033
    

    如果显示如下信息,说明安装成功。

    SuperSU-v2.79-20161205182033.apk: 1 fi.... 184.7 MB/s (6581871 bytes in 0.034s)
    	pkg: /data/local/tmp/SuperSU-v2.79-20161205182033.apk
    Success
    

    注意:!!!将super.apk 安装到模拟器后先不要运行此App!!!

    四、向系统添加su文件

    将下载好的supersu.zip 文件解压,你能看到里面有很多文件夹中都包含su文件。我的模拟器模拟器是Androidx86,所以我在x86文件夹下找到su.pie文件,如果你的android版本是5.1和大于5.1版本的系统使用su.pie比su文件更合适,可以避免出现一些不必要的问题。
    其实用AVD Manager创建的话那个ABI就是的 对应的目录名称
    另外x86_64就是x64,x86对应的是x86
    还有如果文件夹内没有su.pie,没必要一定找那个,su也可以的,只不过优先su.pie的意思。
    在这里插入图片描述
    接下来执行如下命令:
    首先要确保进入abi对应的su.pie所在目录
    命令的大致意思为:在root状态下 adb remount 的意思是 重新挂载系统分区,使系统分区重新可写,一般情况下system下面的文件斯不允许只读的。通过push的方式将su.pie拷贝到/system/xbin/su文件中

    $ adb root
    adbd is already running as root
    $ adb remount
    remount succeeded
    $ adb -e push su.pie /system/xbin/su
    adb: error: cannot stat 'su.pie': No such file or directory
    $ ls
    libsupol.so	su		suinit		sukernel	supolicy
    $ adb -e push su /system/xbin/su
    su: 1 file pushed. 25.3 MB/s (104680 bytes in 0.004s)
    

    看上面的命令是执行在x64的模拟器上,在push su.pie的时候报错了,不存在这个文件,所以在x64架构下直接su就可以了。

    五、修改su文件权限

    执行如下命令:

    $ adb -e shell
    root@generic_x86_64:/ # su root
    root@generic_x86_64:/ # cd /system/xbin
    root@generic_x86_64:/system/xbin # chmod 06755 su
    root@generic_x86_64:/system/xbin # ls -l
    

    查看su的权限如果是下面的结果则表示成功修改权限:

    -rwsr-sr-x root     shell      104680 2008-02-29 10:33 su
    

    六、安装su二进制文件,设置后台守护程序

    # su --install
    # su --daemon&
    

    显示类似如下结果则表示成功

    [1] 4323
    

    七、设置SELinux的限制

    设置SELinux的限制,主要是关闭SELinux,这个命令的具体执行位置没有具体的固定,但貌似在最后执行没有什么问题

    $ setenforce 0
    

    八、安装Root Explorer

    安装这个软件后即可进行系统目录的文件操作了。软件请自行搜索下载。

    写在最后

    如果打开supersu提示错误,可能是su文件不匹配造成的。请尝试从第一步重新安装。在初次打开supersu时,可能提示版本更新,可以直接忽略。选择new user就行。在打开root explorer进行系统目录操作时,会提示root授权,点击grant即可。
    还有就是root后无法通过Avd manager进行启动,需要使用命令行启动

    emulator -avd Pixel_XL_API_26 -writable-system
    

    至此模拟器就成功root。尽情享受吧。

    展开全文
  • Android模拟器

    千次阅读 2019-07-21 15:50:45
    ” 使用Android模拟器开发和调试应用肯定比使用真机方便。但相比XCODE的IOS模拟器,Android SDK自带的AVD实在不争气,不过一些第三方的模拟器却表现不俗! 1、Android SDK自带的AVD模拟器 12年我开始接触Android...
  • Android模拟器知识以及改造

    千次阅读 2018-03-12 09:48:40
     提供了一个Android模拟器,运行流畅度可以类比真机,可以正常运行市面上的大部分应用,比如应用宝,手机管家等。在功能性测试的场景下,比真机节约成本,维护更方便。 2. 原生安卓模拟器的缺点?说Android模拟器...
  • Android studio 三大模拟器比较

    万次阅读 热门讨论 2018-05-11 15:31:15
    自己不对比试试真是不知道卡死了)2.genymotion模拟器-----(缺点:安装有点小麻烦)下载地址:https://www.genymotion.com/download/有免费版本和收费版本,选择免费的就好啦傻瓜式安装,安装完后开始在Android ...
  • Android原生模拟器运行ARM APP

    千次阅读 2019-10-23 19:01:13
    Google原生模拟器运行ARM APPINSTALL_FAILED_NO_MATCHING_ABISGoogle原生APP安装微信(Android 6.0) INSTALL_FAILED_NO_MATCHING_ABIS 安装APK的时候出现这个错误,其实是当你试图安装一个具有本地库的应用程序时,...
  • Android检测模拟器

    千次阅读 2020-06-20 22:11:56
    而因为模拟器所搭载的Android系统是阉割过的,一些安全相关的功能都没有了。这就造成了一个安全问题,在模拟器运行的APP,可被动态调试、抓取数据等,从而增大APP被破解、敏感数据遭泄露的风险。所以一些公司就会...
  • Linux (Ubuntu) 下的Android模拟器:Genymotion

    万次阅读 多人点赞 2015-11-19 11:11:51
    据说这是一款十分好用的Android模拟器,之前没玩过Android模拟器,这就是自己第一次使用。Downloads:https://www.genymotion.com/ 麻烦的是需要现注册才能下载。有收费版,也有免费版,点击buy genymotion,页面往...
  • Android 模拟器不能上网的解决

    千次阅读 2019-02-01 14:17:50
    自己的 电脑可以上网,而android 模拟器不能上网,是因为电脑的DNS与模拟器的DNS不同,可以打开cmd使用ipconfig/all命令查看自己电脑的DNS。因为电脑跟模拟器的DNS不同,会导致不在一个网段,因此模拟器不能上网。 ...
  • Appium搭建五:安装Android模拟器

    千次阅读 2018-11-21 13:54:05
     这里不仅详细介绍了安装Android模拟器的整个过程,而且细致到每一步的安装内容和目的是什么,更好的理解Android模拟器可能需要用到的插件、环境等等。  第三节 安装Android 模拟器  我这里以Android 4.4.2...
  • 告诉大家一个好消息,Google 最近发布了新版 Android 模拟器,将类似冷启动和暖启动的模式引入到模拟器中,号称重启模拟器的时间降低到 6 秒内。我也在第一时间升级体验过,竟然能快至 1 秒启动,简直不要太给力! ...
  • 设置Android模拟器上网的方法

    千次阅读 2018-06-04 14:53:28
    很多网友也问到为啥自己在家的PC机可以上网,而运行在PC机上面的android模拟器却不能上网呢?是因为家里的PC机的DNS一般为:192.168.1.1,这个只是一般而言,不是绝对,这个得自己使用ipconfig /all命令检查下;而...
  • 比真机还快的Android模拟器——Genymotion

    万次阅读 多人点赞 2014-10-15 10:53:27
    比真机还快的Android模拟器——Genymotion 本文引言: 还在为开个程序等半个小时,跑个程序等半天而苦恼不已么?在本节中给大家介绍一款比真机还快的模拟器-Genvmotion 笔者作为一名没收入的大学狗,不像一些在公司工作...
  • 定制Android模拟器skin

    千次阅读 2013-12-09 13:37:05
    Android模拟器提供了6个标准的skin供我们使用,分别对应HVGA(横屏/竖屏)、QVGA(横屏/竖屏)、WQVGA以及WVGA,我们只要在启动模拟器时使用 -skin 参数就可以载入相应的皮肤。这不仅让我们可以随意的修改皮肤的...
  • android 模拟器实现发短信

    千次阅读 2019-03-07 15:32:53
    内容介绍:创建两个Android模拟器,通过一个与另一个进行短信交流。模拟器界面包括两个输入框和一个按钮。在第一个框中输入电话号码,第二个框中输入短信内容,点击按钮发送短信。本文代码在Eclipse中调式完成。 ...
  • Android模拟器尺寸随意改

    千次阅读 2015-01-07 14:58:14
    那么今天大家可以通过对Android模拟器尺寸的大小修改方法进一步对模拟器有一个深入的了解。   Android模拟器提供了4个标准的skin供我们使用,分别对应HVGA(横屏/竖屏)和QVGA(横屏/竖屏),我们只要在启动模拟器...
1 2 3 4 5 ... 20
收藏数 114,295
精华内容 45,718
关键字:

android模拟器