《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);
}
标签:LocateJRE,return,s2,s1,char,源码,jdk8u,NULL,JLI 来源: https://blog.csdn.net/weixin_37477523/article/details/88130214