"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());      ... }
[Java]  纯文本查看  复制代码
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));      ... }
[Java]  纯文本查看  复制代码
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; }
[C]  纯文本查看  复制代码
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); }
[C]  纯文本查看  复制代码
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; }
其中utsname()的定义如下: [C]  纯文本查看  复制代码
1 2 3 4 // kernel-3.10/include/linux/utsname.hstatic inline struct new_utsname *utsname(void) {      return ¤t->nsproxy->uts_ns->name; }
nsproxy 的定义在kernel-3.10/include/linux/nsproxy.h中:
[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
至此,打完收功!

更多相关文章

  1. Android用代码测试Activity的生命周期
  2. Dex2Oat源码流程(1)——Android6.0
  3. Android(安卓)ButterKnife导入使用出错解决
  4. Android(安卓)Gradle 学习之二:重命名APK
  5. Fragment - 用法+demo
  6. Android中App内部切换语言包
  7. Android(安卓)setContentView 源码解析
  8. 布局中@null的代码实现方式
  9. Android系统java层次service实现

随机推荐

  1. 当我凑齐了一整套苹果设备时,我获得了什么
  2. Android中使用Thread+Handler实现非UI线
  3. Android 七彩手电筒的实现与应用
  4. Android高手进阶教程(十五)之---通过Loca
  5. 【Android的从零单排开发日记】之入门篇(
  6. android 通讯录的相关操作
  7. Android输入法遮盖输入框(屏幕底部输入框
  8. Android设备10大不应忽略的功能
  9. Android源码探究:Android(安卓)Java层消息
  10. Android和C环境中遇到的有趣的事情