《jdk8u源码分析》5.3.LocateJRE

src/windows/bin/java_md.c::LocateJRE

/*
 * This is the global entry point. It examines the host for the optimal
 * JRE to be used by scanning a set of registry entries.  This set of entries
 * is hardwired on Windows as "Software\JavaSoft\Java Runtime Environment"
 * under the set of roots "{ HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }".
 *
 * This routine simply opens each of these registry directories before passing
 * control onto ProcessDir().
 */
char *
LocateJRE(manifest_info* info) {
    HKEY    key = NULL;
    char    *path;
    int     key_index;
    HKEY    root_keys[2] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE };

	//遍历注册表分支:HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE
	//搜寻存在注册表子健:JRE_KEY = Software\\JavaSoft\\Java Runtime Environment 的分支
    for (key_index = 0; key_index <= 1; key_index++) {
        if (RegOpenKeyEx(root_keys[key_index], JRE_KEY, 0, KEY_READ, &key)
          == ERROR_SUCCESS)
          	//获取Java Runtime Environment子健下最佳jre的目录地址(值项JavaHome的值)
            if ((path = ProcessDir(info, key)) != NULL) {
                if (key != NULL)
                    RegCloseKey(key);
                //返回最佳jre目录地址
                return (path);
            }
        if (key != NULL)
            RegCloseKey(key);
    }
    return NULL;
}

/*
 * Helpers to look in the registry for a public JRE.
 */
                    /* Same for 1.5.0, 1.5.1, 1.5.2 etc. */
#define JRE_KEY     "Software\\JavaSoft\\Java Runtime Environment"

src/windows/bin/java_md.c::ProcessDir

/*
 * Determine if there is an acceptable JRE in the registry directory top_key.
 * Upon locating the "best" one, return a fully qualified path to it.
 * "Best" is defined as the most advanced JRE meeting the constraints
 * contained in the manifest_info. If no JRE in this directory meets the
 * constraints, return NULL.
 *
 * It doesn't matter if we get an error reading the registry, or we just
 * don't find anything interesting in the directory.  We just return NULL
 * in either case.
 */
static char *
ProcessDir(manifest_info* info, HKEY top_key) {
    DWORD   index = 0;
    HKEY    ver_key;
    char    name[MAXNAMELEN];
    int     len;
    char    *best = NULL;

    /*
     * Enumerate "<top_key>/SOFTWARE/JavaSoft/Java Runtime Environment"
     * searching for the best available version.
     */
    //遍历Java Runtime Environment下面的子目录(jre版本号)
    while (RegEnumKey(top_key, index, name, MAXNAMELEN) == ERROR_SUCCESS) {
        index++;
        //比较注册表中的jre版本号和jar包中的jre版本号,大于注册表中版本号为可接受
        if (JLI_AcceptableRelease(name, info->jre_version))
        	//选取最大的版本号为最佳版本
            if ((best == NULL) || (JLI_ExactVersionId(name, best) > 0)) {
                if (best != NULL)
                    JLI_MemFree(best);
                best = JLI_StringDup(name);
            }
    }

    /*
     * Extract "JavaHome" from the "best" registry directory and return
     * that path.  If no appropriate version was located, or there is an
     * error in extracting the "JavaHome" string, return null.
     */
    if (best == NULL)
        return (NULL);
    else {
    	//打开best对应的注册表键
        if (RegOpenKeyEx(top_key, best, 0, KEY_READ, &ver_key)
          != ERROR_SUCCESS) {
            JLI_MemFree(best);
            if (ver_key != NULL)
                RegCloseKey(ver_key);
            return (NULL);
        }
        JLI_MemFree(best);
        len = MAXNAMELEN;
        //读取其中注册表项JavaHome的值(jre目录地址)到name中
        if (RegQueryValueEx(ver_key, "JavaHome", NULL, NULL, (LPBYTE)name, &len)
          != ERROR_SUCCESS) {
            if (ver_key != NULL)
                RegCloseKey(ver_key);
            return (NULL);
        }
        if (ver_key != NULL)
            RegCloseKey(ver_key);
        //返回最佳jre版本的目录地址
        return (JLI_StringDup(name));
    }
}

src/share/bin/version_comp.c::JLI_AcceptableRelease

/*
 *      Checks if release is acceptable by the specification version-string.
 *      Return true if this version-string (as defined in JSR 56) forms
 *      an acceptable match. A version-string is the union (or) of multiple
 *      elements.
 */
int
JLI_AcceptableRelease(const char *release, char *version_string)
{
    char        *vs;
    char        *m1;
    char        *end;
    m1 = vs = JLI_StringDup(version_string);
    do {
    	//搜索vs中第一次出现' '的位置,如果未找到返回NULL
    	//如果找到,将vs从空格前截断,end指针指向剩余部分(包含空格)
        if ((end = JLI_StrChr(vs, ' ')) != NULL)
            *end = '\0';//end首地址赋值为'\0'
        //比较release, vs,如果vs包含空格,仅比较空格前的部分
        //如果元素无效直接释放内存并返回
        if (acceptable_element(release, vs)) {
            JLI_MemFree(m1);
            return (1);
        }
        //如果vs包含空格,重新将vs赋值指向空格后的字符串,继续循环判断
        if (end != NULL)
            vs = end + 1;
    } while (end != NULL);
    JLI_MemFree(m1);
    return (0);
}

src/share/bin/version_comp.c::acceptable_element

/*
 *      Return true if this element (as defined in JSR 56) forms
 *      an acceptable match. An element is the intersection (and)
 *      of multiple simple-elements.
 */
static int
acceptable_element(const char *release, char *element)
{
    char        *end;
    do {
    	//搜索element中第一次出现'&'的位置,如果未找到返回NULL
    	//如果找到,将element从'&'前截断,end指针指向剩余部分(包含'&')
        if ((end = JLI_StrChr(element, '&')) != NULL)
            *end = '\0';//end首地址赋值为'\0'
        //比较release和element,如果element包含'&',仅比较'&'前的部分
        if (!acceptable_simple_element(release, element))
            return (0);
        //如果element包含空格,重新将vs赋值指向'&'后的字符串,继续循环判断
        if (end != NULL)
            element = end + 1;
    } while (end != NULL);
    return (1);
}

src/share/bin/version_comp.c::acceptable_simple_element

/*
 *      Return true if this simple-element (as defined in JSR 56) forms
 *      an acceptable match.
 *
 *      JSR 56 is modified by the Java Web Start <rel> Developer Guide
 *      where it is stated "... Java Web Start will not consider an installed
 *      non-FCS (i.e., milestone) JRE as a match. ... a JRE from Sun
 *      Microsystems, Inc., is by convention a non-FCS (milestone) JRE
 *      if there is a dash (-) in the version string."
 *
 *      An undocumented caveat to the above is that an exact match with a
 *      hyphen is accepted as a development extension.
 *
 *      These modifications are addressed by the specific comparisons
 *      for releases with hyphens.
 */
static int
acceptable_simple_element(const char *release, char *simple_element)
{
    char        *modifier;
    //判断JRE-Version的是否以 '*' | '+' 结尾
    //如果是,搜索注册表jre版本号是否含有 '-', 有则ASCII比较,否则调用JLI_PrefixVersionId、JLI_ExactVersionId
    modifier = simple_element + JLI_StrLen(simple_element) - 1;
    if (*modifier == '*') {
        *modifier = '\0';
        if (JLI_StrChr(release, '-'))
            return ((JLI_StrCmp(release, simple_element) == 0)?1:0);
        return ((JLI_PrefixVersionId(release, simple_element) == 0)?1:0);
    } else if (*modifier == '+') {
        *modifier = '\0';
        if (JLI_StrChr(release, '-'))
            return ((JLI_StrCmp(release, simple_element) == 0)?1:0);
        return ((JLI_ExactVersionId(release, simple_element) >= 0)?1:0);
    } else {
        return ((JLI_ExactVersionId(release, simple_element) == 0)?1:0);
    }
}

src/share/bin/version_comp.c::JLI_PrefixVersionId

/*
 *      Modeled after strcmp(), compare two version-ids for a Prefix
 *      Match as defined in JSR 56.
 */
int
JLI_PrefixVersionId(const char *id1, char *id2)
{
    char        *s1 = JLI_StringDup(id1);
    char        *s2 = JLI_StringDup(id2);
    char        *m1 = s1;
    char        *m2 = s2;
    char        *end1 = NULL;
    char        *end2 = NULL;
    int res = 0;

    do {
		//判断s1,s2中是否包含分割符,如果包含将分割符前的保留给s1,s2,分隔符及以后的赋值给end1,end2
        if ((s1 != NULL) && ((end1 = JLI_StrPBrk(s1, ".-_")) != NULL))
            *end1 = '\0';
        if ((s2 != NULL) && ((end2 = JLI_StrPBrk(s2, ".-_")) != NULL))
            *end2 = '\0';

        res = comp_string(s1, s2);

        if (end1 != NULL)
            s1 = end1 + 1;
        else
            s1 = NULL;
        if (end2 != NULL)
            s2 = end2 + 1;
        else
            s2 = NULL;

    } while (res == 0 && ((s1 != NULL) && (s2 != NULL)));

    JLI_MemFree(m1);
    JLI_MemFree(m2);
    return (res);
}

src/share/bin/version_comp.c::JLI_ExactVersionId

/*
 *      Modeled after strcmp(), compare two version-ids for an Exact
 *      Match as defined in JSR 56.
 */
int
JLI_ExactVersionId(const char *id1, char *id2)
{
    char        *s1 = JLI_StringDup(id1);
    char        *s2 = JLI_StringDup(id2);
    char        *m1 = s1;
    char        *m2 = s2;
    char        *end1 = NULL;
    char        *end2 = NULL;
    int res = 0;

    do {
		//判断s1,s2中是否包含分割符,如果包含将分割符前的保留给s1,s2,分隔符及以后的赋值给end1,end2
        if ((s1 != NULL) && ((end1 = JLI_StrPBrk(s1, separators)) != NULL))
            *end1 = '\0';
        if ((s2 != NULL) && ((end2 = JLI_StrPBrk(s2, separators)) != NULL))
            *end2 = '\0';
		
		//s1,s2其中一个为NULL,补字符串"0"继续比较
        if ((s1 != NULL) && (s2 == NULL))
            res = comp_string(s1, zero_string);
        else if ((s1 == NULL) && (s2 != NULL))
            res = comp_string(zero_string, s2);
        else
            res = comp_string(s1, s2);

        if (end1 != NULL)
            s1 = end1 + 1;
        else
            s1 = NULL;
        if (end2 != NULL)
            s2 = end2 + 1;
        else
            s2 = NULL;

    } while (res == 0 && ((s1 != NULL) || (s2 != NULL)));

    JLI_MemFree(m1);
    JLI_MemFree(m2);
    return (res);
}

src/share/bin/version_comp.c

/*
 *      A collection of useful strings. One should think of these as #define
 *      entries, but actual strings can be more efficient (with many compilers).
 */
static const char *separators   = ".-_";
static const char *zero_string  = "0";

src/share/bin/version_comp.c::comp_string

/*
 *      Modeled after strcmp(), compare two strings (as in the grammar defined
 *      in Appendix A of JSR 56).  If both strings can be interpreted as
 *      Java ints, do a numeric comparison, else it is strcmp().
 */
static int
comp_string(const char *s1, const char *s2)
{
    jint v1, v2;
    //如果全数字则先求总和再比较差值,否则依次比较ASCII值
    if (isjavaint(s1, &v1) && isjavaint(s2, &v2))
        return ((int)(v1 - v2));
    else
        return (JLI_StrCmp(s1, s2));
}

src/share/bin/version_comp.c::isjavaint

/*
 *      Validate a string as parsable as a "Java int". If so parsable,
 *      return true (non-zero) and store the numeric value at the address
 *      passed in as "value"; otherwise return false (zero).
 *
 *      Note that the maximum allowable value is 2147483647 as defined by
 *      the "Java Language Specification" which precludes the use of native
 *      conversion routines which may have other limits.
 *
 *      Also note that we don't have to worry about the alternate maximum
 *      allowable value of 2147483648 because it is only allowed after
 *      the unary negation operator and this grammar doesn't have one
 *      of those.
 *
 *      Finally, note that a value which exceeds the maximum jint value will
 *      return false (zero). This results in the otherwise purely numeric
 *      string being compared as a string of characters (as per the spec.)
 */
static int
isjavaint(const char *s, jint *value)
{
    jlong sum = 0;
    jint digit;
    //依次遍历字符串中的各个字符,如果有非数字直接返回0
    //如果都为数字则求和返回,如果总和大于jint最大值,返回0
    while (*s != '\0')
        if (isdigit(*s)) {
            digit = (jint)((int)(*s++) - (int)('0'));
            sum = (sum * 10) + digit;
            if (sum > 2147483647)
                return (0);     /* Overflows jint (but not jlong) */
        } else
            return (0);
    *value = (jint)sum;
    return (1);
}

猜你喜欢

转载自blog.csdn.net/weixin_37477523/article/details/88130214