android fwk模块之Sensor架构

news2024/11/27 16:37:21

本文基于Android 12源码整理,包含如下内容:

  • 通信架构
  • 应用层实现
    • 使用方式
    • SensorManager抽象接口具体实现
  • fwk层的实现
    • native中的SensorManager的初始化流程
    • native中的消息队列初始化与数据读取
    • sensorservice实现
  • HAL层的实现

通信架构

在这里插入图片描述

应用层实现

涉及代码:

framework/base/core/java/android/hardware/SensorManager.java
framework/base/core/java/android/hardware/SystemSensorManager.java
framework/base/core/java/android/hardware/SensorEvent.java

使用方式

应用层主要使用fwk提供的SensorManager 来监听获取指定传感器的数据,主要实现如下,
回调的参数SensorEvent是一个包含传感器参数与当前值的数据结构,不同的传感器数据均从其values的float数组中获取值,如光感传感器的值只有一个就是values[0], 陀螺仪有三个值就是values[0],values[1],values[2]等。

import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager

val sm = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sm.registerListener(object : SensorEventListener{
    override fun onSensorChanged(event: SensorEvent?) {
         val x = event?.values?.get(0)
         val y = event?.values?.get(1)
         val z = event?.values?.get(2)
    }
    override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
         //传感器精度回调
    }
}, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), 
									SensorManager.SENSOR_DELAY_NORMAL)

SensorManager抽象接口具体实现

SensorManager是一个抽象函数,部分抽象函数的具体的功能实现是在SystemSensorManager类中, 其构造函数主要做的工作依次如下:

- 初始化jni接口 
- 创建一个SensorManager的native层实例
- 检查当前进程是否具备高速传输传感器数据的权限  
- 初始化本机的sensor设备列表
 public SystemSensorManager(Context context, Looper mainLooper) {
        synchronized (sLock) {
            if (!sNativeClassInited) {
                sNativeClassInited = true;
                //初始化jni接口 
                nativeClassInit();
            }
        }

        mMainLooper = mainLooper;
        ApplicationInfo appInfo = context.getApplicationInfo();
        mTargetSdkLevel = appInfo.targetSdkVersion;
        mContext = context;
        //创建一个SensorManager的native层实例
        mNativeInstance = nativeCreate(context.getOpPackageName());
        mIsPackageDebuggable = (0 != (appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE));
        PackageManager packageManager = context.getPackageManager();
        //检查当前进程是否具备高速传输传感器数据的权限 
        mHasHighSamplingRateSensorsPermission =
                (PERMISSION_GRANTED == packageManager.checkPermission(
                        HIGH_SAMPLING_RATE_SENSORS_PERMISSION,
                        appInfo.packageName));

        // initialize the sensor list
        for (int index = 0;; ++index) {
            Sensor sensor = new Sensor();
            //初始化本机的sensor设备列表
            if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break;
            mFullSensorsList.add(sensor);
            mHandleToSensor.put(sensor.getHandle(), sensor);
        }
    }

每个app在通过getSystemService获取class类型为SensorManager的对象时,获取的都是SystemSensorManager对象,实例的初始化在SystemServiceRegistry的静态域中初始化,代码如下:

registerService(Context.SENSOR_SERVICE, SensorManager.class,
                new CachedServiceFetcher<SensorManager>() {
     @Override
     public SensorManager createService(ContextImpl ctx) {
         Return new SystemSensorManager(ctx.getOuterContext(),
     ctx.mMainThread.getHandler().getLooper());
}});

再跟一下监听函数registerListener,最终会走到SystemSensorManager的registerListenerImpl函数中,实现功能如下:

- 检查注册参数是否符合要求
- 获取监听器实例的所有事件队列
      -> 如果队列为空   
           1.创建新的队列实例
           2.队列实例中加入当前监听的Sensor对象
           3.将事件队列加入到监听器的HashMap中对应保存
      -> 如果队列不为空
           1.队列实例中加入当前监听的Sensor对象

实现代码如下:

// Invariants to preserve:
// - one Looper per SensorEventListener
// - one Looper per SensorEventQueue
// We map SensorEventListener to a SensorEventQueue, which holds the looper
synchronized (mSensorListeners) {
    SensorEventQueue queue = mSensorListeners.get(listener);
    if (queue == null) {
        Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
        final String fullClassName =listener.getClass().getEnclosingClass() != null
                            ? listener.getClass().getEnclosingClass().getName()
                            : listener.getClass().getName();
        queue = new SensorEventQueue(listener, looper, this, fullClassName);
        if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) {
              queue.dispose();
              return false;
        }
        mSensorListeners.put(listener, queue);
        return true;
    } else {
        return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs);
    }
}

SensorEventQueue 是定义在SystemSensorManager.java文件中的一个静态内部类,其父类类型为BaseEventQueue,BaseEventQueue中定义了enableSensor, 在app注册了监听器后,BaseEventQueue会调用nativeEnableSensor去激活该Sensor. SensorEventQueue中还实现了dispatchSensorEvent函数,当底层上报数据的时候,JNI层会回调该函数,将数据传给listener实例。

 protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
                long timestamp) {
            final Sensor sensor = mManager.mHandleToSensor.get(handle);
            if (sensor == null) {
                // sensor disconnected
                return;
            }

            SensorEvent t = null;
            synchronized (mSensorsEvents) {
                t = mSensorsEvents.get(handle);
            }

            if (t == null) {
                // This may happen if the client has unregistered and there are pending events in
                // the queue waiting to be delivered. Ignore.
                return;
            }
            // Copy from the values array.
            System.arraycopy(values, 0, t.values, 0, t.values.length);
            t.timestamp = timestamp;
            t.accuracy = inAccuracy;
            t.sensor = sensor;

            // call onAccuracyChanged() only if the value changes
            final int accuracy = mSensorAccuracies.get(handle);
            if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
                mSensorAccuracies.put(handle, t.accuracy);
                mListener.onAccuracyChanged(t.sensor, t.accuracy);
            }
            mListener.onSensorChanged(t);
        }

fwk层的实现

涉及代码如下:

frameworks/base/core/jni/android_hardware_SensorManager.cpp
frameworks/native/libs/sensor/*
frameworks/native/services/sensorservice/*

SensorManager的jni实现,定义在android_hardware_SensorManager.cpp这个文件中,这里不全部介绍每个本地函数的功能,只挑几个重要的

native中的SensorManager的初始化流程

android_hardware_SensorManager.cpp

//初始化native层SensorManager
static jlong
nativeCreate(JNIEnv *env, jclass clazz, jstring opPackageName)
{
    ScopedUtfChars opPackageNameUtf(env, opPackageName);
    return (jlong) &SensorManager::getInstanceForPackage(String16(opPackageNameUtf.c_str()));
}

SensorManager.cpp文件路径在frameworks/native/libs/sensor文件夹下,该库编译后生成libsensor.so给到libandroid_server.so依赖,该库是一个通信中间件,实现了Sensor数据的同一进程内unix域通信,以及通过binder通信来实现部分Sensor的设置项实现。Sensor的jni类就是靠引入该库的头文件来实现与Sensor Service通信的。

获取SensorManager实例

frameworks/native/libs/sensor/SensorManager.cpp

SensorManager& SensorManager::getInstanceForPackage(const String16& packageName) {
    waitForSensorService(nullptr);

    Mutex::Autolock _l(sLock);
    SensorManager* sensorManager;
    //sPackageInstances是一个map数据结构,key是const String16,value是SensorManager指针
    auto iterator = sPackageInstances.find(packageName);
    //如果这个包已经获取过SensorManager,直接把返回该实例的指针
    if (iterator != sPackageInstances.end()) {
        sensorManager = iterator->second;
    } else {
        String16 opPackageName = packageName;
         //权限检测,判断当前调用的包名是不是有权限访问sensor
        if (opPackageName.size() <= 0) {
            sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
            if (binder != nullptr) {
                const uid_t uid = IPCThreadState::self()->getCallingUid();
                Vector<String16> packages;
                interface_cast<IPermissionController>(binder)->getPackagesForUid(uid, packages);
                if (!packages.isEmpty()) {
                    opPackageName = packages[0];
                } else {
                    ALOGE("No packages for calling UID");
                }
            } else {
                ALOGE("Cannot get permission service");
            }
        }
        //创建一个新的SensorManager对象
        sensorManager = new SensorManager(opPackageName);

        // If we had no package name, we looked it up from the UID and the sensor
        // manager instance we created should also be mapped to the empty package
        // name, to avoid looking up the packages for a UID and get the same result.
        if (packageName.size() <= 0) {
            sPackageInstances.insert(std::make_pair(String16(), sensorManager));
        }

        // Stash the per package sensor manager.
        sPackageInstances.insert(std::make_pair(opPackageName, sensorManager));
    }

    return *sensorManager;
}

native中的消息队列初始化与数据读取

在这里插入图片描述
上图包括了一个native中消息队列创建的完整流程,在之前讲过registerListener的数据主要来自SensorEventQueue的dispatchSensorEvent, 这个java层的方法回调是由JNI实现中的Receiver函数来触发的,Receiver是LooperCallback的子类,实际可以看成Handler的Native样式,这个函数的dispatchEvent中会一直循环从native层的SensorEventQueue中去read数据,read函数的实现在libsensor.so库中的BitTube.cpp实现,因为sensorservice与sensor jni均运行在system_server进程内,故这里数据的读写使用unix同进程内的域通信来实现的。具体的通信实现可以看BitTube.cpp这个文件。

sensorservice实现

上面一节分析完了,Sensor数据是在jni中的Receiver中通过JNI反射java层函数,调用Java层的SensorEventQueue中的dispatchSensorEvent函数发给各个app的, Receiver通过libsensor.so不断从server端去read数据,这里Receiver可以看作是一个客户端,那么服务端的实现就是sensorservice, 其实现在frameworks/native/services/sensorservice下,这个服务的作用就是起到承上启下的作用,对上作为aidl的BnBinder端供BpBinder调用,作为Socket的Server端,往Client端写数据;对下,则是作为一个hidl的client端,通过调用hal层的sensor服务接口,来联通上下层。其主要流程如下:


 - threadLoop函数中循环通过SensorDevice去poll数据,并通过SensorEventConnect的sendEvents发送到jni函数的Receiver中
 - SensorDevice.cpp 顾名思义就是传感器设备,该类实现了HIDL的接口,并通过hidl与hal层实现数据的poll以及设置的接口调用,列表的初始化等。
 - SensorEventConnection.cpp是一个事件处理通道,保持了与client进行unix域通信的双句柄,通过调用SensorEventQueue的write函数实现将sensor数据发送到client端(JNI中的Receiver类)。

threadLoop函数poll数据的实现:

SensorService.cpp

bool SensorService::threadLoop() {
    ALOGD("nuSensorService thread starting...");
    ...
    ...
    //SensorDevice是单例模式的
    SensorDevice& device(SensorDevice::getInstance());
    //获取hal层版本
    const int halVersion = device.getHalDeviceVersion();
    do {
        //poll数据
        ssize_t count = device.poll(mSensorEventBuffer, numEventMax);
        if (count < 0) {
            if(count == DEAD_OBJECT && device.isReconnecting()) {
                device.reconnect();
                continue;
            } else {
                ALOGE("sensor poll failed (%s)", strerror(-count));
                break;
            }
        }

        // Reset sensors_event_t.flags to zero for all events in the buffer.
        for (int i = 0; i < count; i++) {
             mSensorEventBuffer[i].flags = 0;
        }
        
        //省略了很多代码

	    //将数据发送到所有通道
        for (const sp<SensorEventConnection>& connection : activeConnections) {
            //发送数据
            connection->sendEvents(mSensorEventBuffer, count, mSensorEventScratch,
                    mMapFlushEventsToConnections);
            needsWakeLock |= connection->needsWakeLock();
            // If the connection has one-shot sensors, it may be cleaned up after first trigger.
            // Early check for one-shot sensors.
            if (connection->hasOneShotSensors()) {
                cleanupAutoDisabledSensorLocked(connection, mSensorEventBuffer, count);
            }
        }
    }while (!Thread::exitPending());
}

SensorDevice的poll功能实现

ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
    if (mSensors == nullptr) return NO_INIT;

    ssize_t eventsRead = 0;
    if (mSensors->supportsMessageQueues()) {
        eventsRead = pollFmq(buffer, count);//从mSensors的消息队列读值
    } else if (mSensors->supportsPolling()) {
        eventsRead = pollHal(buffer, count); //调用mSensors的poll函数取值
    } else {
        ALOGE("Must support polling or FMQ");
        eventsRead = -1;
    }
    return eventsRead;
}


mSensors变量类型定义如下:

sp<::android::hardware::sensors::V2_1::implementation::ISensorsWrapperBase> mSensors;

这个类型是由hidl生成的,定义在hardware/interfaces/sensors/2.1/default下,厂商自定义实现该功能。

SensorEventConnection sendEvents的实现

SensorEventConnection.cpp

status_t SensorService::SensorEventConnection::sendEvents(
        sensors_event_t const* buffer, size_t numEvents,
        sensors_event_t* scratch,
        wp<const SensorEventConnection> const * mapFlushEventsToConnections) 
        //... 省略很多代码
       ssize_t size = SensorEventQueue::write(mChannel,
                                    reinterpret_cast<ASensorEvent const*>(scratch), count);
	 //... 省略很多代码
}

SensorEventQueue实现在libsensor.so里面,write函数就是调用了内部的网络通信封装的类BitTube.cpp来实现写入。

HAL层的实现

hal层的实现基本上每个厂商的实现都不一样,这里只跟了一下原生的,涉及到的源码如下:

hardware/libhardware/include/hardware/sensors.h
hardware/libhardware/include/hardware/sensors-base.h
hardware/interfaces/sensors/*

sensors.h定义了sensor的各类数据结构,如sensor的数据格式,sensor对应hal层的module,sensor device格式,以及实现了动态管理客制化的sensor hal实现的库或者驱动的接口。

/** convenience API for opening and closing a device */
static inline int sensors_open(const struct hw_module_t* module,
        struct sensors_poll_device_t** device) {
    return module->methods->open(module,
            SENSORS_HARDWARE_POLL, TO_HW_DEVICE_T_OPEN(device));
}

static inline int sensors_close(struct sensors_poll_device_t* device) {
    return device->common.close(&device->common);
}

static inline int sensors_open_1(const struct hw_module_t* module,
        sensors_poll_device_1_t** device) {
    return module->methods->open(module,
            SENSORS_HARDWARE_POLL, TO_HW_DEVICE_T_OPEN(device));
}

static inline int sensors_close_1(sensors_poll_device_1_t* device) {
    return device->common.close(&device->common);
}

sensors-base.h则定义了SENSOR设备类型的值。

hardware/interfaces/sensors/1.0/default/Sensors.cpp中实现了对sensor module的load,以及设备的加载。

Sensors::Sensors()
    : mInitCheck(NO_INIT),
      mSensorModule(nullptr),
      mSensorDevice(nullptr) {
    status_t err = OK;
    if (UseMultiHal()) {
        mSensorModule = ::get_multi_hal_module_info();
    } else {
        //hal层动态加载module的so库, hw_get_module的实现在hardware/libhardware/hardware.c中,是要是动过dlopen动态加载so库。
        err = hw_get_module(
            SENSORS_HARDWARE_MODULE_ID,
            (hw_module_t const **)&mSensorModule);
    }
    if (mSensorModule == NULL) {
        err = UNKNOWN_ERROR;
    }

    if (err != OK) {
        LOG(ERROR) << "Couldn't load "
                   << SENSORS_HARDWARE_MODULE_ID
                   << " module ("
                   << strerror(-err)
                   << ")";

        mInitCheck = err;
        return;
    }
    //从module涨获取到sensor设备,后续的操作都需要mSensorDevice才能与真实的硬件设备通讯
    err = sensors_open_1(&mSensorModule->common, &mSensorDevice);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/345381.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C#开发的OpenRA的只读字典IReadOnlyDictionary实现

C#开发的OpenRA的只读字典IReadOnlyDictionary实现 怎么样实现一个只读字典? 这是一个高级的实现方式,一般情况下,开发人员不会考虑这个问题的。 毕竟代码里,只要小心地使用,还是不会出问题的。 但是如果在一个大型的代码,或者要求比较严格的代码里,就需要考虑这个问题了…

51单片机——中断系统之外部中断实验,小白讲解,相互学习

中断介绍 中断是为使单片机具有对外部或内部随机发生的事件实时处理而设置的&#xff0c;中断功能的存在&#xff0c;很大程度上提高了单片机处理外部或内部事件的能力。它也是单片机最重要的功能之一&#xff0c;是我们学些单片机必须要掌握的。 为了更容易的理解中断概念&…

1.3配置P2P网络类型

1.3.1实验3:配置P2P网络类型 实验需求实现单区域OSPF的配置实现通过display命令查看OSPF的网络类型实验拓扑实验拓扑如图1-11所示 图1-11 配置P2P网络类型 实验步骤步骤1:[1] 配置IP地址 路由器R1

关于“档案大数据”的非主流看法

近日&#xff0c;反复拜读了前国家档案局局长杨冬权先生今年6.9档案日的大作《从“选时代”到“全时代”——智慧社会档案工作的历史性转折》&#xff0c;作为档案信息化从业者那真是倍感振奋&#xff0c;壮怀激烈&#xff01; 这篇文章绝对可以用气势磅礴、高屋建瓴这样的词语…

Oracle Data Guard 角色转换(Role Transitions)

查询视图V$DATABASE的DATABASE_ROLE列可以看到数据库当前的角色。 1&#xff0e;角色转换介绍 Oracle Data Guard让你可以使用SQL语句或者通过Oracle Data Guard broker界面来动态更改数据库的角色&#xff0c;Oracle Data Guard支持以下的角色转换&#xff1a; 1&#xff0…

C语言——指针、数组的经典笔试题目

文章目录前言1.一维数组2.字符数组3.二维数组4.经典指针试题前言 1、数组名通常表示首元素地址&#xff0c;sizeof(数组名)和&数组名两种情况下&#xff0c;数组名表示整个数组。 2、地址在内存中唯一标识一块空间&#xff0c;大小是4/8字节。32位平台4字节&#xff0c;64位…

hive数据存储格式

1、Hive存储数据的格式如下&#xff1a; 存储数据格式存储形式TEXTFILE行式存储SEQUENCEFILE行式存储ORC列式存储PARQUET列式存储 2、行式存储和列式存储 解释&#xff1a; 1、上图左面为逻辑表&#xff1b;右面第一个为行式存储&#xff0c;第二个温列式存储&#xff1b; …

【C语言】程序环境和预处理|预处理详解|定义宏(上)

主页&#xff1a;114514的代码大冒险 qq:2188956112&#xff08;欢迎小伙伴呀hi✿(。◕ᴗ◕。)✿ &#xff09; Gitee&#xff1a;庄嘉豪 (zhuang-jiahaoxxx) - Gitee.com 文章目录 目录 文章目录 前言 一、程序的翻译环境和执行环境 二、详解编译和链接 1.翻译环境 2.编…

TCP协议十大特性

日升时奋斗&#xff0c;日落时自省 目录 1、确认应答 1.1、序号编辑 2、超时重传 3、连接管理 3.1、三次握手 3.2、四次挥手 4、滑动窗口 5、流量控制 6、拥塞控制 7、延时应答 8、捎带应答 9、面向字节流 10、异常情况 TCP协议&#xff1a; 特点&#xff1a;有…

浅析EasyCVR安防视频能力在智慧小区建设场景中的应用及意义

一、行业需求 城市的发展创造了大量工作机会&#xff0c;人口的聚集也推动了居民住宅建设率的增长。人民生活旨在安居乐业&#xff0c;能否住得“踏实”是很多劳动工作者最关心的问题。但目前随着住宅小区规模的不断扩大、人口逐渐密集&#xff0c;在保证居住环境舒适整洁的同…

C++入门:初识类和对象

C入门&#xff1a;类和对象1 本节目录C入门&#xff1a;类和对象11.auto关键字&#xff08;C11)1.1类型别名思考1.2auto简介typeid运算符&#xff1a;获取类型信息1.3 auto的使用细则1.4auto不能推到的场景2.基于范围的for循环(C11)2.1范围for的语法2.2范围for的使用条件3.指针…

SpringCloud篇——什么是SpringCloud、有什么优缺点、学习顺序是什么

文章目录一、首先看官方解释二、Spring Cloud 的项目的位置三、Spring Cloud的子项目四、Spring Cloud 现状五、spring cloud 优缺点六、Spring Cloud 和 Dubbo 对比七、Spring Cloud 学习路线一、首先看官方解释 Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式…

【Azure 架构师学习笔记】-Azure Logic Apps(6)- Logic Apps调用ADF

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Logic Apps】系列。 接上文【Azure 架构师学习笔记】-Azure Logic Apps&#xff08;5&#xff09;- 标准和使用量类型的区别 前言 Logic Apps 和 ADF 的搭配使用是常见的组合&#xff0c;它们可以互相弥补各自的不足和…

opencv绘制椭圆

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人的博客_CSDN博客-微信小程序,前端,python领域博主lqj_本人擅长微信小程序,前端,python,等方面的知识https://blog.csdn.net/lbcyllqj?spm1011.2415.3001.5343哔哩哔哩欢迎关注…

ViT自适应patch划分 ACM MM 2021

Transformer在计算机视觉方面取得了巨大的成功&#xff0c;而如何分割图像中的patch仍然是一个问题。现有的方法通常使用固定大小的patch embedding&#xff0c;这可能会破坏对象的语义。为了解决这一问题&#xff0c;作者提出了一种新的Deformable Patch模块&#xff08;DPT&a…

CPP2022-30-期末模拟测试03

6-1 引用作函数形参交换两个整数 分数 5 全屏浏览题目 切换布局 作者 李廷元 单位 中国民用航空飞行学院 设计一个void类型的函数Swap&#xff0c;该函数有两个引用类型的参数&#xff0c;函数功能为实现两个整数交换的操作。 裁判测试程序样例&#xff1a; #include <…

Linux网络:聚合链路技术

目录 一、聚合链路技术 1、bonding作用 2、Bonding聚合链路工作模式 3、Bonding实现 一、聚合链路技术 1、bonding作用 将多块网卡绑定同一IP地址对外提供服务&#xff0c;可以实现高可用或者负载均衡。直接给两块网卡设置同一IP地址是不可以的。通过 bonding&#xff0c…

微信小程序DAY2

文章目录DAY2一、学习目标二、数据绑定2-1、插值表达式![请添加图片描述](https://img-blog.csdnimg.cn/f433301ae5de4094bc397a8c5ea216d7.png)2-2、Mustache语法的应用场景2-2-1、绑定属性2-2-2、三元运算三、事件绑定3-1、事件对象的属性列表3-2、target 和 currentTarget 的…

Win12呼之欲出

Win10系统的电子授权将要停止&#xff0c;20H2、21H2两个版本未来也没有非安全更新了&#xff0c;只剩下Win10 22H2最新版还会继续更新功能&#xff1b;考虑到Win10庞大的基数&#xff0c;至少10亿台电脑的装机量依然是不可忽视的&#xff0c;所以Win10马上被淘汰是不可能的&am…

Linux内核转储---Kdump,Crash使用介绍

文章目录Kdump简介Crash简介Ubuntu下安装使用方法Crash相关命令crash基本用法crash的基本命令help&#xff1a;crash所提供的调试命令log&#xff1a;查看日志信息&#xff0c;类似dmesg输出bt&#xff1a;查看异常时候的堆栈信息dev: 查看设备的情况dis&#xff1a;反汇编代码…