Android logd日志简介及典型案例分析

news2024/11/27 18:42:11

在程序开发过程中,日志打印属于最普遍的操作,是代码调试和验证过程必不可少的手段。在Android开发过程中,我们经常通过Log\Slog等方式写入日志,然后通过对应的logcat命令读取相应的日志信息。具体日志如何写入或者读出,系统代码如何调用,可能也没有深入研究过。本文就通过具体的流程、框架设计、源码分析等讨论下Android日志的读写过程,以及介绍往往遇到日志丢失的场景及典型案例分析。

1、日志接口

日志接口内容,共分为java层、native层、kernel层等。下面就对每个层级的内容分别进行介绍。

1.1 java层调用接口

b2fdc8358750da94bbd54079932a49d7.png

日志级别分别为VERBOSE、DEBUG、INFO、WARN、ERROR、ASSERT,日志级别依次提升。默认定义了5个buffer缓冲区,分别是main、radio、events、system、crash,对应的ID信息分别为LOG_ID_MAIN、LOG_ID_RADIO、LOG_ID_EVENTS、LOG_ID_SYSTEM、 LOG_ID_CRASH。

f3270b32141287bb7e5f66d3285eccef.png

1.1.1 日志缓冲区简介

Android日志记录系统守护进程logd维护的一组结构化环形缓冲区,这组可用的缓冲区是固定的,且由系统定义。也可以通过logcat 命令查看如下缓冲区。

radio:查看包含无线装置/电话相关消息的缓冲区,可以调用android.telephony.Rlog打印日志。

events:查看经过解译的二进制系统时间缓冲区信息,类型为events的日志是用来诊断系统问题的。在应用框架提供了android.util.EventLog接口通过liblog动态库往日志驱动程序中写入日志,运行时库提供了宏LOG_EVENT_INT、LOG_EVENT_LONG、LOG_EVENT_FLOAT、LOG_EVENT_STRING用来写入events类型日志。

main:查看主日志缓冲区信息,main日志缓冲区是应用程序唯一可用的日志缓冲区,在应用框架中提供了android.util.Log接口通过liblog动态库往日志驱动程序中写入日志,运行时库提供了LOGV、LOGD、LOGI、LOGW、LOGE等宏用来写入main类型的日志。

system:查看系统缓冲区类型为system的日志,在应用框架提供了android.util.SLog接口通过liblog动态库往日志驱动程序中写入日志,运行时库提供了SLOGV、SLOGD、SLOGI、SLOGW、SLOGE等宏用来写入system类型的日志。

crash:查看崩溃日志缓冲区的日志信息。

1.1.2 命令查看缓冲区日志信息

ogcat -b + 参数查看对应缓冲区内容,具体见如下内容。

all:查看所有缓冲区日志

default:查看main、system、crash三个缓冲区日志信息

比如:logcat -b main用来查看main缓冲区信息;logcat -b main,system用来查看main和system缓冲区信息;logcat -b all 查看所有缓冲区信息。

1.2 native层接口调用

原生系统日志接口封装在liblog.so库中,供native层代码调用。最终通过socket的通信方式将日志写入logd的buffer中。具体调用过程需要引入liblog动态库,然后才能调用如下native层的日志接口__android_log_print,很多内容都封装成ALOGX的接口,具体内容可参考如下所示:

#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)

#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG  , LOG_TAG, __VA_ARGS__)

#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO   , LOG_TAG, __VA_ARGS__)

#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN   , LOG_TAG, __VA_ARGS__)

#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR  , LOG_TAG, __VA_ARGS__)

1.3 kernel层调用接口

经常使用的接口是printk,具体用法如下:

printk(KERN_INFO "\n");  //KERN_INFO为日志级别,"\n"则为日志信息。

日志级别信息如下:

kernel日志级别分别是:KERN_EMERG,KERN_ALERT,KERN_CRIT,KERN_ERR,KERN_WARNING,KERN_NOTICE,KERN_INFO,KERN_DEBUG

原生代码kern_levels.h中定义如下

#define KERN_EMERGKERN_SOH "0"/* system is unusable */

#define KERN_ALERTKERN_SOH "1"/* action must be taken immediately */

#define KERN_CRITKERN_SOH "2"/* critical conditions */

#define KERN_ERRKERN_SOH "3"/* error conditions */

#define KERN_WARNINGKERN_SOH "4"/* warning conditions */

#define KERN_NOTICEKERN_SOH "5"/* normal but significant condition */

#define KERN_INFOKERN_SOH "6"/* informational */

#define KERN_DEBUGKERN_SOH "7"/* debug-level messages */

日志输出到/proc/kmsg节点,用户可以通过cat节点信息获取kernel日志信息。

2、logd守护进程

2.1 整体设计架构

2.1.1 logd架构设计图

a6c91a8b2ff52461677ba0a3ebcb5330.png

架构设计图内容简介如下:

dc942f146cf450802563d989114446f7.png

logd启动过程还存在其他内容,比如LogStatistics :是日志统计模块,默认开启统计数据较少,仅能以 pid/uid 维度统计打印日志的数量。

整体日志打印过程:用户调用java层接口,通过JNI调用走到native层(native层接口调用直接加载liblog调用接口输入日志),加载liblog动态库,通过socket通信将日志写入和读取,最终输出到对应的文件或者控制台。

2.1.2 命令查看logd进程内容

2.1.2.1 logd进程内容如下图所示:

dc2f06f269f5f7d5117ba43a37a56e2f.png

2.1.2.2 logd线程内容简介

acf6ccff0a8cb41174e5fb4e0a8faa58.png

2.2 logd启动内容

logd作为native service,系统启动过程通过读取rc文件来启动,相关的属性定义在如下logd.rc文件中。

2.2.1 logd启动过程

4f860e7a2f963c460722b81a643df65a.png

logd启动后会存在三个用来服务日志系统的socket:分别是

/dev/socket/logd、/dev/socket/logdr、/dev/socket/logdw。

c675f0d5f43daf85c89991836f9744da.png

2.2.2 日志打印buffer缓冲区

如下代码中的参数LOG_ID_MAIN:代表buffer缓冲区,DEBUG:代表日志级别。java层调用和native层调用存在轻微差异,很容易进行辨别。native的级别和buffer比较全面,大家可以通过源码参考下。具体的日志buffer缓冲区及日志等级,见下图所示。

/XXX/frameworks/base/core/java/android/util/Log.java

/**

 * Send a {@link #DEBUG} log message.

* @param tag Used to identify the source of a log message.  It usually identifies

*        the class or activity where the log call occurs.

* @param msg The message you would like logged.

* @return A positive value if the message was loggable (see {@link #isLoggable}).

*/

public static int d(@Nullable String tag, @NonNull String msg) {

    return println_native(LOG_ID_MAIN, DEBUG, tag, msg);

}

db9b1bb130b55fc4fbc9b3df441640b7.png

a9208567b9e1c19dadde69700fbc2430.png

2.2.3 Android日志与logd交互过程

2.2.3.1 Android日志传递给logd

Android app层或framework层,通过调用Log/Slog/Rlog中d方法打印日志,通过JNI会调用到native层android_util_Log_println_native接口,具体见下图内容。

05a1c812b8d2553b77872af946bf570f.png

接下来具体调用流程如下:

/XXX/system/logging/liblog/logger_write.cpp

__android_log_buf_write

  -->__android_log_write_log_message

     -->get_logger_function()

        -->__android_log_logd_logger

           -->write_to_log

              -->LogdWrite

最终写到 “/dev/socket/logdw”中,此时logd中的LogListener会监测到存在log信息需要写入,待log保存到buffer中后,再通知LogReader将新保存的log传递给logcat等

socket信息如下

// Note that it is safe to call connect() multiple times on DGRAM Unix domain sockets, so this

// function is used to reconnect to logd without requiring a new socket.

static void LogdConnect(int sock) {

sockaddr_un un = {};

un.sun_family = AF_UNIX;

    strcpy(un.sun_path, "/dev/socket/logdw");

    TEMP_FAILURE_RETRY(connect(sock, reinterpret_cast(&un), sizeof(sockaddr_un)));

}

2.2.3.2 logd中的log保存过程

具体代码路径如/XXX/system/logging/logd/main.cpp,从文件的main函数中可以看到,logd执行过程中创建了LogBuffer,LogReader,LogListener和CommandListener四个对象,上文有详细介绍,本节暂且不予解释,详情见2.3.1.2节内容。

a2bd528edf77cb37cb5a791b90272a74.png

接下来创建LogListener的对象,开启一个线程“logd.writer”监听数据,具体过程见下图。

979bf3dfb6ba0a8ff74373b316e79d1c.png

HandleData()

-->logbuf_->Log

新建一个LogBufferElement对象,实现log的保存.

2.2.3.3 logcat获取logd日志

/XXX/system/logging/logcat/logcat.cpp

int main(int argc, char** argv) {

Logcat logcat;

return logcat.Run(argc, argv);

}

具体的logcat命令参数解析在Run函数中执行。

f0ef0e73aff19074b003248f70d3bf73.png

379d72066dd94af1f152cf10ea7f723c.png

android_logger_list_read接下来的调用过程如下:

android_logger_list_read

-->LogdRead //打开logdr,并通过socket获取log

-->logdOpen

5516ea6b025356aacdf1279f85f1c73f.png

logd的main函数中有开启LogReader监听

// LogReader listens on /dev/socket/logdr. When a client

// connects, log entries in the LogBuffer are written to the client.

LogReader* reader = new LogReader(log_buffer, &reader_list);

if (reader->startListener()) {

  return EXIT_FAILURE;

}

LogReader继承自SocketListener,如果socket监听到数据,则执行onDataAvailable函数进行处理。

70ad70e8cd864b5fd18f177dabd5f5ed.png

86fbda2b3e7c93b5f6d7150ac6c6eacd.png

2ffa8e80b77fbd6a36102329b47b33a7.png

最后加入read_list_中:

d29b98b97a0da3b253f074e1268c6ebf.png

最终通过ProcessBuffer输出日志内容,打印log_msg日志到界面或者fd文件中。具体内容包括:处理日志buffer内容、回滚打印日志内容等。

2.3 kernel日志写入logd介绍

通过logcat命令获取kernel日志比较特殊,故作为一个例子进行梳理。

2.3.1 整体流程

0da472f4ecfa09211b485b3bb758ae4e.png

2.3.2 命令打印kernel日志

通过logcat -b kernel获取kernel日志,依赖于如下属性值,具体查看源码xxx/system/logging/logd/main.cpp中有体现。

b1da63478de7da92718d65d81303d6ec.png

2.3.3 详细总结流程

2.3.3.1 logd的日志流程

712876cdc9f98eab66e1bab45f937972.png

35c35d9cc7de2c66b802be4d403f85e3.png

3b6f3aa82afdeb3fc3ac369283012de6.png

32d51b95325c388a86506ad7fc40abaa.png

1a918b064a49f177be1bcedcb7da397e.png

2.3.3.2 监听kernel log

8f3c58037303f6e0946770acf1f3e77d.png

4f958fb8431413946b315673c4790bc1.png

b91cbf493b6dad9f69f5f12ae12b0c15.png

b0a05de06d06c094174252374278982c.png

2.3.3.3 SocketListener关于onDataAvailable的回调

67bd44e20e9ac3666e3d86be68571b9f.png

da293dcf40cf716147bbf22a7986e26f.png

2861b36c2295ea4f1298f2d8e600137d.png

2.3.3.4 日志写入LOG_ID_KERNEL buffer中

42e9341ced6e4a21be5a60681cdd3be1.png

8253fd310ad670c0a8de803f0fbe7842.png

38fc2767e28e2452062bdcbd291ad2da.png

2.3.3.4 kernel日志buffer的流程

6067adf4b44f518b2bb1c427b7cc6ecf.png

此流程细节内容,建议辅助查看源码分析。

3、logcat命令介绍

具体的参数使用可以通过命令查看,或者查看具体的源码,当然直接查看命令较为方便。

3.1 logcat帮助命令

e602a305aa91997e8ffc4ada7d4a8093.png

3.2 日志等级:

7f9bb93106e9ce759416110d7dd0d768.png

3.3 查看缓冲区buffer:

logbuffer默认设置在LogSize.h文件中

db3c4bf59ba2140846603d8fd2e84537.png

命命令查看buffer如下:

701b677a0ec7ffd2925a0b63f93811ab.png

3.4 命令抓取日志

logcat -b main -b system -b crash -r 1024 -n 5 -f android.log -v threadtime

-b:加载可供查看的缓冲区的日志

-b main:抓取main缓冲区的日志;

-b system:抓取system缓冲区的日志;

-b crash:抓取crash缓冲区的日志;

-r:每次输出多大日志文件后进行轮替

-r 1024:代表每份文件日志最大size为1024KB,也就是1M

-n:日志输出最大数目,最多是n+1份

-n 5:日志文件输出最多5+1=6份

-f:logcat日志内容保存的位置

-f android.log:日志输出文件目录

-v:设置日志消息输出格式

-v:threadtime 显示日期,调用时间,优先级,标记,以及发出消息的线程的pid和tid信息

如上命令抓取日志流程如下,具体查看logcat.cpp的源码

dd0f66451d5460190a3a4f892a02b57a.png

直到停止日志打印操作,则结束日志输出文件的流程。

3.5 具体命令操作展示

建议参考如下命令,在终端设备模拟练习。

f03aeb260d3a218d3fed384e0cb964e7.png

b835fed6c0bd897b471419a47b868d57.png

4、典型案例分析

下面针对一些典型场景缺通用日志(android/kernel)的问题,一一列举如下,希望可以让大家关注到缺日志的真实原因。如下问题也提醒各位工程师:  谨慎添加日志,不要随意添加,否则即容易造成自己的日志缺失也会导致其他业务模块丢失日志。

通用日志丢失目前有如下情况会出现:

(1) liblog通过socket传输日志时失败,此时在event日志中会记录类似上图中tag=liblog的埋点。具体见4.1、4.2节内容。

(2) 其它进程通过socket读取logd的日志时,此时由于日志打印速度过快,读取速度跟不上写入速度,造成了部分历史日志被丢弃的情况,此时在event日志中会记录tag=chatty的埋点。此种情况遇到较少。

(3) logd buffer中日志内存超过buffer大小了,则会按照每次裁剪日志的行数等于日志总行数的10%,并且会大于等于4行,小于256行。环形buffer大小超过了,会不断循环裁剪。

(4) 文件存储问题,导致日志内容无法落盘至日志文件。具体见4.3节内容。

(5) 低内存查杀日志进程,导致日志内容无法落盘。具体见4.4节内容。

日志丢失的问题可能不止以上原因,基本分析思路是首先了解问题发生场景及时间点,然后通过日志抓取和落盘场景进行分析,参考业务日志打印频率、logd的状态(logd的cpu负载、运行状态)、系统的异常状态(严重低内存、整机CPU负载高、文件系统异常、温度过高限频限核)等综合原因,得出问题分析结论。往往日志缺失和系统状态联系较为紧密,所以分析此类问题,就要具备开阔的视野,能够及时联想到有关整机各个状态,推测和佐证自己的分析原因和得出的结论。具体分析过程,也可以参考思维导图。

17e49489ad42fd0dbadf01cd7f40b89e.png

下面针对以上内容,列举如下几个典型案例,仅供大家参考。

4.1 业务日志输出频率太高

(1) events日志出现大量丢弃日志打印

b85c99cb548b3d2a155b7fa5e434322f.png

(2) 查看android日志,发现sensor日志打印量非常大,基本达到刷屏的程度

809802d2326e869e4de7700697e8e3ef.png

(3) android日志输出频率达4229条/秒,日志输出频率非常大,sensor日志打印处于top1,达到2418条/s。

总结:sensor日志打印频率太高,超过了socket的处理能力,不能及时处理只能先行丢掉。故导致部分日志丢失。

4.2 整机负载高

(1) 输出的日志出现大量的日志丢失内容

e242bec56a939ebecc8f14a4b103aaeb.png

(2) 查看日志打印频率,发现日志输出频率较低

(3) 查看systrace发现整机负载高达90%以上,logd一直处于runanble状态,整机温度也较高导致触发了限频限核。

b69b5c61f67cddd1dbbfdb7008e7b842.png

总结:logd一直处于runnable状态,导致logd无法获得cpu时间片执行日志操作,容易出现socket通信失败,故导致部分日志丢失。

4.3 存储异常导致

(1) 查看日志发现mmap异常

5c698077469e237ad65dfe96ccf64e64.png

(2) 由于没有过多日志打印,故本地使用adb logcat抓取日志分析

c7916aad0ab9f8943a99632287d14168.png

总结:文件存储出现问题,日志无法输出到对应的文件中,日志信息无法得到落盘,故出现日志内容大量丢失。

4.4 低内存导致

(1) 日志文件为空

ee7df542345056c4079df0c15427eed3.png

(2) kernel日志中发现打印日志进程被杀

57135ba8acfa1c545b810adb3d0265c7.png

(3) 查看内存,已经处于低内存状态

3c15f2783049252c8b95532ec8c78978.png

总结:低内存导致日志进程被杀,出现日志文件无对应的日志信息落盘,故出现日志内容丢失。

还有其他原因,欢迎大家补充交流!

5、资源消耗问题

打印日志是非常消耗资源的,原因可概括如下:

(1) 跨进程通信的消耗:日志信息通过 socket 发送给 logd,存在跨进程通信的消耗;

(2) 内存消耗:logd 中维持对应的buffer,存在相应RAM的消耗,往往低存储机器在低内存过程表现尤为突出;

(3) CPU资源消耗:logd中ring buffer会经常进行 pruneLogs操作,进行删减日志,会耗费一定的CPU资源;业务日志打印太多容易导致logd在一段时间出现cpu负载非常高的现象;

(4) IO消耗:在应用程序中 ,创建后台线程保存日志信息,这会导致应用或者整机卡顿。

(5) 功耗消耗:往往业务日志打印较多,导致logd的cpu负载非常高,直观表现就是发热和续航恶化。

(6) 性能消耗:日志打印过多,也容易导致界面操作卡顿,从而表现出整机性能方面的消耗。

所以,规劝大家在打印日志过程一定要注意。在正式版本中,一定要规范日志打印,要有系统资源消耗及整机性能的意识。最好建立自己模块的故障检测能力,平时做到少量日志打印,遇到故障可以适当增加日志打印。

文中有些不对的内容,也欢迎大家及时指正,期待与您一块成长!

参考文档:

https://www.jianshu.com/p/4b08af887fb7

https://blog.csdn.net/mafei852213034/article/details/117780317

手机投屏之WFD简介

ARM NEON在矩阵&向量计算中的加速

OPPO在CLK大会上公布可编程内核技术,引领安卓流畅体验升级

59512626ea97bc14225c9f2ed6d133d0.gif

长按关注内核工匠微信

Linux内核黑科技| 技术文章| 精选教程

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

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

相关文章

oracle查询数据库内全部的表名、列明、注释、数据类型、长度、精度等

Oracle查询数据库内全部的表名、列明、注释、数据类型、长度、精度 SELECT a.TABLE_NAME 表名, row_number() over(partition by a.TABLE_NAME order by a.COLUMN_NAME desc) 字段顺序,a.COLUMN_NAME 列名, b.COMMENTS 注释,a.DATA_TYPE 数据类型, a.DATA_LENGTH 长度,DATA_SC…

Linux高级命令(扩展)二

一、Linux下用户管理 1、用户概念以及基本作用 用户:指的是Linux操作系统中用于管理系统或者服务的人 一问:管理系统到底在管理什么? 答:Linux下一切皆文件,所以用户管理的是相应的文件 二问:如何管理…

SpringBoot集成Redis客户端

文章目录 Redis 的 Java 客户端Spring Data Redis 介绍Spring Data Redis 使用方式 Redis 的 Java 客户端 Redis 的 Java 客户端很多,常用的几种: JedisLettuceSpring Data Redis Spring Data Redis 介绍 Spring Data Redis 是 Spring 的一部分&…

跨境电商年底风控升级,测评养号如何选择稳定且纯净的IP环境?

随着年底跨境电商平台风控的升级,许多测评团队的账号存活率有所下降。对于自养号测评的卖家来说,IP的重要性不言而喻。除了设置参数阻断,IP的质量也直接影响到账户的稳定性和成功率。因此,在年底这个特殊时期,所有测评…

Kali Linux:网络与安全专家的终极武器

文章目录 一、Kali Linux 简介二、Kali Linux 的优势三、使用 Kali Linux 进行安全任务推荐阅读 ——《Kali Linux高级渗透测试》适读人群内容简介作者简介目录 Kali Linux:网络与安全专家的终极武器 Kali Linux,对于许多网络和安全专业人士来说&#x…

【APUE】并发 — 线程

目录 一、线程的概念 1.1 定义 1.2 POSIX 线程标准 1.3 线程标识 1.4 相关函数 1.5 一些补充 二、线程的创建、终止与取消 2.1 创建 2.2 终止 2.2.1 return 2.2.2 pthread_exit 2.3 取消 2.3.1 函数介绍 2.3.2 禁止线程被取消 2.3.3 线程取消方式 2.4 清…

第7章_单行函数

文章目录 1 函数的理解1.1 什么是函数1.2 不同DBMS函数的差异 2 数值函数2.1 基本函数2.2 角度与弧度2.3 三角函数2.4 指数函数、对数函数2.5 进制间的转换 3 字符串函数4 日期和时间函数4.1 获取日期、时间4.2 日期与时间戳的转换4.3 获取月份、星期、星期数、天数4.4 日期的操…

零代码复现-TCGA联合GEO免疫基因结合代谢基因生信套路(二)

零代码复现-TCGA联合GEO免疫基因结合代谢基因生信套路(二)-关键基因集的获取和生存数据准备 前面的分析中,下载TCGA和GEO的数据,并进行简单的处理,接下来就是相关基因集的获取和整理,为后期聚类和降维做准…

[ element-ui:table ] 设置table中某些行数据禁止被选中,通过selectable 定义方法解决

业务需求:需要做到table表格中某些行数据不能被选中,比如在审核一些记录数据时,已经被审核的数据就不能再次提交审核,特别是批量多选的情况,列表中既有已经审核的,也有未审核的,只要求选中未审核…

USB Type-C reference circuit

1.OTG功能,只能对负载供电,不能从电脑端给板子供电 2. USB TTL作为usb串口,可以从电脑端给板子供电 3.USB Type-C power supply,仅仅用来从USB电源得到工作电压。但是外部电源供电电压must supply 12V or greater. 4.功能完整的USB3.0 T…

​实现1个电脑打开多个微信​

实现1个电脑打开多个微信:1、快速双击打开微信,可打开多个微信。2、按住回车键,双击打开微信,并快速放开回车键即可打开多个微信。3、用命令符也可打开多个微信。4、建立一个批处理文件实现打开多个微信。 方法一:最简…

飞书开发学习笔记(一)-应用创建和测试

飞书开发学习笔记(一)-应用创建和测试 一.前言 现在大企业用的办公IM软件中,飞书是口碑最好的,不得不说,字节在开发产品方面,确实有自己独到的竞争力,比如说抖音、头条、飞书。在办公会议和云文档的体验上,其它的办公…

[JavaWeb]——过滤器filter与拦截器Interceptor的使用、执行过程、区别

🌈键盘敲烂,年薪30万🌈 目录 一、过滤器filter 概念介绍: 过滤器的使用: 过滤器的执行流程: 应用场景(登录校验): 二、拦截器Interceptor 概念介绍: 拦截器的使用&#xff1…

智慧建筑工地管理平台源码

智慧工地是聚焦工程施工现场,紧紧围绕人、机、料、法、环等关键要素,综合运用物联网、云计算、大数据、移动计算和智能设备等软硬件信息技术,与施工生产过程相融合。 智慧工地管理平台充分运用数字化技术,聚焦施工现场岗位一线&am…

生成带分表和水印的excel压缩文件

功能描述 将查询结果生成带分表和水印的excel压缩文件 功能点 1、将查询结果导出为excel文件 2、每个表格存放50万条数据&#xff0c;超过50万条数据&#xff0c;生成新的分表 3、生成的表格需要添加水印 4、将生成的全部分表&#xff0c;打包成zip压缩文件 引入依赖 <…

【鸿蒙软件开发】ArkUI之Column、ColumnSplit组件

文章目录 前言一、Column1.1 子组件1.2 接口参数 1.3 属性1.4 示例代码 二、ColumnSplit2.1 子组件2.2 接口2.3 属性2.4 示例代码 总结 前言 Column容器组件&#xff1a;沿垂直方向布局的容器。 ColumnSplit组件&#xff1a;将子组件纵向布局&#xff0c;并在每个子组件之间插…

迈巴赫S480升级主动式氛围灯 浪漫又婉转的气氛

主动式氛围灯有263个可多色渐变的LED光源&#xff0c;营造出全情沉浸的动态光影氛围。结合智能驾驶辅助系统&#xff0c;可在转向或检测到危险时&#xff0c;予以红色环境光提示&#xff0c;令光影艺术彰显智能魅力。配件有6个氛围灯&#xff0c;1个电脑模块。 1、气候&#x…

操作系统的线程模型

操作系统的线程调度有几个重要的概念&#xff1a; 调度器&#xff08;Thread Scheduler&#xff09;&#xff1a;内核通过操纵调度器对内核线程进行调度&#xff0c;并负责将线程的任务映射到各个处理器上内核线程&#xff08;Kernel Level Thread&#xff09;&#xff1a;简称…

企业文件防泄密软件哪个好?文件防泄密软件如何选择

企业文件防泄密软件哪个好&#xff1f;文件防泄密软件如何选择 安企神数据防泄密系统下载使用 在互联网迅速发展的大环境下&#xff0c;数据已经成为企业发展的重要资产之一&#xff0c;然而&#xff0c;随着网络攻击手段的不断升级&#xff0c;企业数据泄露事件屡见不鲜&…

机器学习笔记 - 感知器的数学表达

一、假设前提 感知机(或称感知器,Perceptron)是Frank Rosenblatt在1957年就职于Cornell航空实验室(Cornell Aeronautical Laboratory)时所发明的一种人工神经网络。 它可以被视为一种最简单形式的前馈神经网络,是一种二元线性分类模型,其输入为实例的特征向量,输出为实…