"Kernel version" 中编译时间的前世今生
16lz
2021-01-26
"Kernel version" 中编译时间的前世今生
我们经常为固定编译时间,这个时间一般是指 Settings -> About phone -> Kernel version 中的时间,那么,这个时间到底怎么来的呢?
Settings中用于显示Kernel version的关键代码如下: [Java] 纯文本查看 复制代码1 2 3 4 5 6 7 8 | // packages/apps/Settings/src/com/android/settings/DeviceInfoSettings.java public void onCreate(Bundle icicle) { ... // 设置版本号 findPreference(KEY_KERNEL_VERSION).setSummary(getFormattedKernelVersion()); ... } |
1 2 3 4 5 6 7 8 | // packages/apps/Settings/src/com/android/settings/DeviceInfoSettings.java public static String getFormattedKernelVersion() { ... // 从"/proc/version"文件中读取编译信息,通过解析,组合出想要显示的版本号 return formatKernelVersion(readLine(FILENAME_PROC_VERSION)); ... } |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // packages/apps/Settings/src/com/android/settings/DeviceInfoSettings.java public static String formatKernelVersion(String rawKernelVersion) { // Example (see tests for more): // Linux version 3.0.31-g6fb96c9 ([url=mailto:android-build@xxx.xxx.xxx.xxx.com]android-build@xxx.xxx.xxx.xxx.com[/url]) \ // (gcc version 4.6.x-xxx 20120106 (prerelease) (GCC) ) #1 SMP PREEMPT \ // Thu Jun 28 11:02:39 PDT 2012 final String PROC_VERSION_REGEX = "Linux version (\\S+) " + /* group 1: "3.0.31-g6fb96c9" */ "\\((\\S+?)\\) " + /* group 2: "x@y.com" (kernel builder) */ "(?:\\(gcc.+? \\)) " + /* ignore: GCC version information */ "(#\\d+) " + /* group 3: "#1" */ "(?:.*?)?" + /* ignore: optional SMP, PREEMPT, and any CONFIG_FLAGS */ "((Sun|Mon|Tue|Wed|Thu|Fri|Sat).+)"; /* group 4: "Thu Jun 28 11:02:39 PDT 2012" */ // 解析版本信息 Matcher m = Pattern.compile(PROC_VERSION_REGEX).matcher(rawKernelVersion); ... // 组合出想要的版本号 return m.group( 1 ) + "\n" + // 3.0.31-g6fb96c9 m.group( 2 ) + " " + m.group( 3 ) + "\n" + // [url=mailto:x@y.com]x@y.com[/url] #1 m.group( 4 ); // Thu Jun 28 11:02:39 PDT 2012 } |
我们可以看到,Kernel version是通过解析"/proc/version"文件得到的,而"/proc/version" 则是被"kernel-3.10/fs/proc/version.c"生成的:
[C] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | //kernel-3.10/fs/proc/version.c // 创建 "/proc/version" 文件后用到的回调函数 static const struct file_operations version_proc_fops = { .open = version_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int __init proc_version_init( void ) { // 创建 "/proc/version" 文件, 并注册回调函数 proc_create( "version" , 0, NULL, &version_proc_fops); return 0; } |
1 2 3 4 5 6 7 | // kernel-3.10/fs/proc/version.c // 创建完成后通过回调函数调用 static int version_proc_open( struct inode *inode, struct file *file) { // 打开"/proc/version" 文件, 并注册回调函数"version_proc_show()" return single_open(file, version_proc_show, NULL); } |
01 02 03 04 05 06 07 08 09 10 11 12 13 | //kernel-3.10/fs/proc/version.c // 打开文件完成后通过回调函数调用 static int version_proc_show( struct seq_file *m, void *v) { // 输出编译信息到"/proc/version" 文件 // "linux_proc_banner"为format string,定义 kernel-3.10/init/version.c 中 // utsname(),内联函数,定义在 kernel-3.10/include/linux/utsname.h 中 seq_printf(m, linux_proc_banner, utsname()->sysname, utsname()->release, utsname()->version); // version 包括了编译时间 return 0; } |
1 2 3 4 | // kernel-3.10/include/linux/utsname.hstatic inline struct new_utsname *utsname(void) { return ¤t->nsproxy->uts_ns->name; } |
[C] 纯文本查看 复制代码
1 2 3 4 5 6 7 8 | // kernel-3.10/include/linux/nsproxy.h struct nsproxy { atomic_t count; struct uts_namespace *uts_ns; struct ipc_namespace *ipc_ns; struct mnt_namespace *mnt_ns; struct pid_namespace *pid_ns; struct net *net_ns; }; |
uts_ns的初始化在kernel-3.10/kernel/nsproxy.c中:
[C] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 | // kernel-3.10/kernel/nsproxy.c struct nsproxy init_nsproxy = { .count = ATOMIC_INIT(1), .uts_ns = &init_uts_ns, #if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC) .ipc_ns = &init_ipc_ns, #endif .mnt_ns = NULL, .pid_ns = &init_pid_ns, #ifdef CONFIG_NET .net_ns = &init_net, #endif }; |
可以看到uts_ns = &init_uts_ns, init_uts_ns的定义在kernel-3.10/init/version.c 中:
[C] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | // kernel-3.10/init/version.c struct uts_namespace init_uts_ns = { .kref = { .refcount = ATOMIC_INIT(2), }, .name = { .sysname = UTS_SYSNAME, .nodename = UTS_NODENAME, .release = UTS_RELEASE, .version = UTS_VERSION, .machine = UTS_MACHINE, .domainname = UTS_DOMAINNAME, }, .user_ns = &init_user_ns, .proc_inum = PROC_UTS_INIT_INO, }; |
我们可以看到version = UTS_VERSION,UTS_VERSION这个宏定义在compile.h中,这是一个生成文件,是被 kernel-3.10/scripts/mkcompile_h 这个脚本生成的,生成路径为(g3557为当前所编译的项目名):
./out/target/product/g3557/obj/KERNEL_OBJ/include/generated/compile.h [Shell] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # kernel-3.10/scripts/mkcompile_h # 通过抓Log,$KBUILD_BUILD_TIMESTAMP 为空 if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then # 获取系统当前的日期和时间 TIMESTAMP=` date ` else TIMESTAMP=$KBUILD_BUILD_TIMESTAMP fi # 组合出UTS_VERSION UTS_VERSION= "$UTS_VERSION $CONFIG_FLAGS $TIMESTAMP" # Generate a temporary compile.h ( echo /\* This file is auto generated, version $VERSION \*/ if [ -n "$CONFIG_FLAGS" ] ; then echo "/* $CONFIG_FLAGS */" ; fi echo \ #define UTS_MACHINE \"$ARCH\" # 输出UTS_VERSION 到compile.h echo \ #define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\" echo \ #define LINUX_COMPILE_BY \"`echo $LINUX_COMPILE_BY | $UTS_TRUNCATE`\" echo \ #define LINUX_COMPILE_HOST \"`echo $LINUX_COMPILE_HOST | $UTS_TRUNCATE`\" echo \ #define LINUX_COMPILER \"`$CC -v 2>&1 | tail -n 1`\" ) > .tmpcompile |
更多相关文章
- Android用代码测试Activity的生命周期
- Dex2Oat源码流程(1)——Android6.0
- Android(安卓)ButterKnife导入使用出错解决
- Android(安卓)Gradle 学习之二:重命名APK
- Fragment - 用法+demo
- Android中App内部切换语言包
- Android(安卓)setContentView 源码解析
- 布局中@null的代码实现方式
- Android系统java层次service实现