android 教你如何判断是否是模拟器还是真机

最近有一些业务需求要判断是否在真机上运行还是在模拟器上运行两种不同的情况下做不同的业务逻辑操作。上网查了查还真有不少的资源。接下来老于接给大家们来总结一下。主要思路:

1.  首先要明白 不要采用IMEI的方式。模拟器的IMEI可以修改的。而且平板是没有IMEI的,可以检测设备的MAC地址,模拟器的MAC地址是固定的几种。

2.通过调用公开或者隐藏的系统API判断并不靠谱,因为调用结果可以轻易被修改,比如直接修改Android的源代码或者借助Xposed Framework进行修改。
3.有基于模拟器特征和api返回值的检测方法都可以通过修改安卓源码的方式轻松绕过。模拟器与真机的本质区别在于运行载体。鉴于大多数的安卓模拟器基于qemu,qemu在执行程序时实际上是将其翻译成宿主机的指令,比如将安卓的arm指令翻译成PC的x86指令。为了效率上的考虑,qemu在翻译执行arm指令时并没有实时更新模拟的pc寄存器值,只会在一段代码翻译执行完之后再更新,而真机中pc寄存器是一直在更新的。基于这一点,可以设计一段CPU任务调度程序来检测模拟器 。具体的你可以参鉴DexLab上的一篇文章。当然,这个方法也是可以被绕过的,可以在理解qemu源码的基础上,修改qemu源码,但很明显这个门槛很高 。

 // 系统在启动的时候会做一次判断,看看SystemServer.java里是怎么判断的:
    private void initData(){
        boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
        if (isEmulator) {
            Slog.i(TAG, "No Bluetooh Service (emulator)");
        } else if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            Slog.i(TAG, "No Bluetooth Service (factory test)");
        } else if (!context.getPackageManager().hasSystemFeature
                (PackageManager.FEATURE_BLUETOOTH)) {
            Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
        } else if (disableBluetooth) {
            Slog.i(TAG, "Bluetooth Service disabled by config");
        } else {
            Slog.i(TAG, "Bluetooth Service");
            mSystemServiceManager.startService(BluetoothService.class);
        }

    }
  系统在启动的时候会做一次判断,看看SystemServer.java里是怎么判断的:
  private void initData(){
        boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
        if (isEmulator) {
            Slog.i(TAG, "No Bluetooh Service (emulator)");
        } else if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            Slog.i(TAG, "No Bluetooth Service (factory test)");
        } else if (!context.getPackageManager().hasSystemFeature
                (PackageManager.FEATURE_BLUETOOTH)) {
            Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
        } else if (disableBluetooth) {
            Slog.i(TAG, "Bluetooth Service disabled by config");
        } else {
            Slog.i(TAG, "Bluetooth Service");
            mSystemServiceManager.startService(BluetoothService.class);
        }

    }
 //第二种方式   读取文件内容,然后检查已知QEmu的驱动程序的列表
private static String[]known_qemu_drivers = {"goldfish" };
public static Boolean CheckQEmuDriverFile(){
    File driver_file =new File("/proc/tty/drivers");
    if(driver_file.exists()&& driver_file.canRead()){
        byte[]data =new byte[(int)driver_file.length()];
        try{
            InputStream inStream =new FileInputStream(driver_file);
            inStream.read(data);
            inStream.close();
        }catch (FileNotFoundException e){
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }catch (IOException e){
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        String driver_data =new String(data);
        for(String known_qemu_driver : known_qemu_drivers){
            if(driver_data.indexOf(known_qemu_driver)!= -1){
                Log.v("Result:","Find known_qemu_drivers!");
                return true;
            }
        }
    }
    Log.v("Result:","Not Find known_qemu_drivers!");
    return false;
}
第三种方式检测模拟器上特有的几个文件
private static String[]known_numbers = {"15555215554","15555215556",
        "15555215558","15555215560","15555215562","15555215564",
        "15555215566","15555215568","15555215570","15555215572",
        "15555215574","15555215576","15555215578","15555215580",
        "15555215582","15555215584",};

public static Boolean CheckPhoneNumber(Context context){
    TelephonyManager telephonyManager =(TelephonyManager)context
            .getSystemService(Context.TELEPHONY_SERVICE);

    String phonenumber =telephonyManager.getLine1Number();

    for(String number :known_numbers){
        if(number.equalsIgnoreCase(phonenumber)){
            Log.v("Result:","Find PhoneNumber!");
            return true;
        }
    }
    Log.v("Result:","Not Find PhoneNumber!");
    return false;
}
//第五中方式 ----》 检测设备IDS 是不是 “000000000000000”
private static String[]known_device_ids = {"000000000000000" // 默认ID
};

public static Boolean CheckDeviceIDS(Context context){
    TelephonyManager telephonyManager = (TelephonyManager)context
            .getSystemService(Context.TELEPHONY_SERVICE);

    String device_ids =telephonyManager.getDeviceId();

    for(String know_deviceid : known_device_ids){
        if(know_deviceid.equalsIgnoreCase(device_ids)){
            Log.v("Result:","Find ids: 000000000000000!");
            return true;
        }
    }
    Log.v("Result:","Not Find ids: 000000000000000!");
    return false;
}
//第六种方式 检测imsi id是不是“310260000000000”
private static String[]known_imsi_ids = {"310260000000000" // 默认的 imsi id
    };
    public static Boolean CheckImsiIDS(Context context){
        TelephonyManager telephonyManager =(TelephonyManager)
                context.getSystemService(Context.TELEPHONY_SERVICE);

        String imsi_ids =telephonyManager.getSubscriberId();

        for(String know_imsi :known_imsi_ids){
            if(know_imsi.equalsIgnoreCase(imsi_ids)){
                Log.v("Result:","Find imsi ids: 310260000000000!");
                return true;
            }
        }
        Log.v("Result:","Not Find imsi ids: 310260000000000!");
        return false;
    }
//第七种方式   检测手机上的一些硬件信息
public static Boolean CheckEmulatorBuild(Context context){
    String BOARD =android.os.Build.BOARD;
    String BOOTLOADER =android.os.Build.BOOTLOADER;
    String BRAND =android.os.Build.BRAND;
    String DEVICE =android.os.Build.DEVICE;
    String HARDWARE =android.os.Build.HARDWARE;
    String MODEL =android.os.Build.MODEL;
    String PRODUCT =android.os.Build.PRODUCT;
    if(BOARD== "unknown"|| BOOTLOADER== "unknown"
            ||BRAND =="generic" ||DEVICE =="generic"
            ||MODEL =="sdk" ||PRODUCT =="sdk"
            ||HARDWARE =="goldfish")
    {
        Log.v("Result:","Find Emulator by EmulatorBuild!");
        return true;
    }
    Log.v("Result:","Not Find Emulator by EmulatorBuild!");
    return false;
}
//第八种方式 ---》   检测手机运营商家
public static boolean CheckOperatorNameAndroid(Context context){
    String szOperatorName = ((TelephonyManager)
            context.getSystemService(Context.TELEPHONY_SERVICE)).getNetworkOperatorName();

    if(szOperatorName.toLowerCase().equals("android")== true){
        Log.v("Result:","Find Emulator by OperatorName!");
        return true;
    }
    Log.v("Result:","Not Find Emulator by OperatorName!");
    return false;
}
最后要注意的是在PC操作系统上的某些恶意软件会判断是不是在虚拟机上运行。
老于的博客地址: http://blog.csdn.net/androidstarjack
另外你觉得此篇文章对您有所帮助 请加 QQ交流群 :232203809    
此外还可以关注终端研发部


评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

androidstarjack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值