"Kernel version" 中编译时间的前世今生

来源:互联网 发布:debian和ubuntu哪个好 编辑:程序博客网 时间:2024/05/17 02: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
 
publicvoid 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
 
publicstatic String getFormattedKernelVersion() {
    ...
        // 从"/proc/version"文件中读取编译信息,通过解析,组合出想要显示的版本号
        returnformatKernelVersion(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
 
publicstatic 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
 
    finalString 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);
    ...
 
    // 组合出想要的版本号
    returnm.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" 文件后用到的回调函数
staticconst struct file_operations version_proc_fops = {
    .open        = version_proc_open,
    .read        = seq_read,
    .llseek      = seq_lseek,
    .release     = single_release,
};
 
staticint __init proc_version_init(void)
{
    // 创建 "/proc/version" 文件, 并注册回调函数
    proc_create("version", 0, NULL, &version_proc_fops);
    return0;
}
[C] 纯文本查看 复制代码
1
2
3
4
5
6
7
// kernel-3.10/fs/proc/version.c
// 创建完成后通过回调函数调用
staticint version_proc_open(structinode *inode, structfile *file)
{
    // 打开"/proc/version" 文件, 并注册回调函数"version_proc_show()"
    returnsingle_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
// 打开文件完成后通过回调函数调用
staticint version_proc_show(structseq_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 包括了编译时间
    return0;
}
其中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
structnsproxy {    atomic_t count;
    structuts_namespace *uts_ns;
    structipc_namespace *ipc_ns;
    structmnt_namespace *mnt_ns;
    structpid_namespace *pid_ns;
    structnet           *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
structnsproxy 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
structuts_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 fileis auto generated, version $VERSION \*/
  if[ -n "$CONFIG_FLAGS"] ; thenecho "/* $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
至此,打完收功!
0 0