SDK: Extract find_java static library.
Change-Id: Ic8b2130a327d73c044c0931509385aed19f78a9e
diff --git a/sdkmanager/win_android/win_android.cpp b/sdkmanager/win_android/win_android.cpp
index 2c957e0..6417051 100644
--- a/sdkmanager/win_android/win_android.cpp
+++ b/sdkmanager/win_android/win_android.cpp
@@ -27,20 +27,9 @@
#ifdef _WIN32
-#define _CRT_SECURE_NO_WARNINGS 1
+#include "utils.h"
+#include "find_java.h"
-#include <direct.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <windows.h>
-
-// VS vs MINGW specific includes
-#ifdef USE_MINGW
- #define _ASSERT(x) // undef
-#else
- #include <crtdbg.h> // for _ASSERT
-#endif
// A NULL-terminated list of directory to create in the temp folder.
static const char * sMkDirList[] = {
@@ -69,467 +58,6 @@
NULL,
};
-static bool gDebug = false;
-
-
-// An array that knows its own size. Not dynamically resizable.
-template <class T> class CArray {
- T* mPtr;
- int mSize;
-public:
- explicit CArray(int size) {
- mSize = size;
- mPtr = new T[size];
- }
-
- ~CArray() {
- if (mPtr != NULL) {
- delete[] mPtr;
- mPtr = NULL;
- }
- mSize = 0;
- }
-
- T& operator[](int i) {
- _ASSERT(i >= 0 && i < mSize);
- return mPtr[i];
- }
-
- int size() const {
- return mSize;
- }
-};
-
-// A simple string class wrapper.
-class CString {
-protected:
- char *mStr;
-public:
- CString() { mStr = NULL; }
- CString(const CString &str) { mStr = str.mStr == NULL ? NULL : _strdup(str.mStr); }
- explicit CString(const char *str) { mStr = NULL; set(str); }
- CString(const char *start, int length) { mStr = NULL; set(start, length); }
-
- CString& set(const char *str) {
- _free();
- if (str != NULL) {
- mStr = _strdup(str);
- }
- return *this;
- }
-
- CString& set(const char *start, int length) {
- _free();
- if (start != NULL) {
- mStr = (char *)malloc(length + 1);
- strncpy(mStr, start, length);
- mStr[length] = 0;
- }
- return *this;
- }
-
- CString& setv(const char *str, va_list ap) {
- _free();
- // _vscprintf(str, ap) is only available with the MSVCRT, not MinGW.
- // Instead we'll iterate till we have enough space to generate the string.
- int len = strlen(str) + 1024;
- mStr = (char *)malloc(len);
- strcpy(mStr, str); // provide a default in case vsnprintf totally fails
- for (int guard = 0; guard < 10; guard++) {
- int ret = vsnprintf(mStr, len, str, ap);
- if (ret == -1) {
- // Some implementations don't give the proper size needed
- // so double the space and try again.
- len *= 2;
- } else if (ret >= len) {
- len = ret + 1;
- } else {
- // There was enough space to write.
- break;
- }
- mStr = (char *)realloc((void *)mStr, len);
- strcpy(mStr, str); // provide a default in case vsnprintf totally fails
- }
- return *this;
- }
-
- CString& setf(const char *str, ...) {
- _free();
- va_list ap;
- va_start(ap, str);
- setv(str, ap);
- va_end(ap);
- return *this;
- }
-
- virtual ~CString() { _free(); }
-
- // Returns the C string owned by this CString. It will be
- // invalid as soon as this CString is deleted or out of scope.
- const char * cstr() const {
- return mStr;
- }
-
- bool isEmpty() const {
- return mStr == NULL || *mStr == 0;
- }
-
- int length() const {
- return mStr == NULL ? 0 : strlen(mStr);
- }
-
- CString& add(const char *s) {
- if (mStr == NULL) {
- set(s);
- } else {
- mStr = (char *)realloc((void *)mStr, strlen(mStr) + strlen(s) + 1);
- strcat(mStr, s);
- }
- return *this;
- }
-
- CArray<CString> * split(char sep) const {
- if (mStr == NULL) {
- return new CArray<CString>(0);
- }
- const char *last = NULL;
- int n = 0;
- for (const char *s = mStr; *s; s++) {
- if (*s == sep && s != mStr && (last == NULL || s > last+1)) {
- n++;
- last = s;
- }
- }
-
- CArray<CString> *result = new CArray<CString>(n);
- last = NULL;
- n = 0;
- for (const char *s = mStr; *s; s++) {
- if (*s == sep) {
- if (s != mStr && (last == NULL || s > last+1)) {
- const char *start = last ? last : mStr;
- (*result)[n++].set(start, s-start);
- }
- last = s+1;
- }
- }
-
- return result;
- }
-
-private:
- void _free() {
- if (mStr != NULL) {
- free((void *)mStr);
- mStr = NULL;
- }
- }
-
-};
-
-// A simple path class wrapper.
-class CPath : public CString {
-public:
- CPath() : CString() { }
- CPath(const CPath &str) : CString(str) { }
- explicit CPath(const char *str) : CString(str) { }
- CPath(const char *start, int length) : CString(start, length) { }
-
- // Appends a path segment, adding a \ as necessary.
- CPath& addPath(const CString &s) {
- return addPath(s.cstr());
- }
-
- // Appends a path segment, adding a \ as necessary.
- CPath& addPath(const char *s) {
- _ASSERT(s != NULL);
- if (s != NULL && s[0] != 0) {
- int n = length();
- if (n > 0 && s[0] != '\\' && mStr[n-1] != '\\') add("\\");
- add(s);
- }
- return *this;
- }
-
- // Returns true if file exist and is not a directory.
- // There's no garantee we have rights to access it.
- bool fileExists() const {
- if (mStr == NULL) return false;
- DWORD attribs = GetFileAttributesA(mStr);
- return attribs != INVALID_FILE_ATTRIBUTES &&
- !(attribs & FILE_ATTRIBUTE_DIRECTORY);
- }
-
- // Returns true if file exist and is a directory.
- // There's no garantee we have rights to access it.
- bool dirExists() const {
- if (mStr == NULL) return false;
- DWORD attribs = GetFileAttributesA(mStr);
- return attribs != INVALID_FILE_ATTRIBUTES &&
- (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
- }
-
- // Returns a copy of the directory portion of the path, if any
- CPath dirName() const {
- CPath result;
- if (mStr != NULL) {
- char *pos = strrchr(mStr, '\\');
- if (pos != NULL) {
- result.set(mStr, pos - mStr);
- }
- }
- return result;
- }
-
- // Returns a pointer to the baseName part of the path.
- // It becomes invalid if the path changes.
- const char * baseName() const {
- if (mStr != NULL) {
- char *pos = strrchr(mStr, '\\');
- if (pos != NULL) {
- return pos + 1;
- }
- }
- return NULL;
- }
-
- // If the path ends with the given searchName, replace in-place by the new name
- void replaceName(const char *searchName, const char* newName) {
- if (mStr == NULL) return;
- int n = length();
- int sn = strlen(searchName);
- if (n < sn) return;
- // if mStr ends with searchName
- if (strcmp(mStr + n - sn, searchName) == 0) {
- int sn2 = strlen(newName);
- if (sn2 > sn) {
- mStr = (char *)realloc((void *)mStr, n + sn2 - sn + 1);
- }
- strcpy(mStr + n - sn, newName);
- mStr[n + sn2 - sn] = 0;
- }
- }
-};
-
-// ========= UTILITIES ==============
-
-// Displays a message in an ok+info dialog box.
-static void msgBox(const char* text, ...) {
- CString formatted;
- va_list ap;
- va_start(ap, text);
- formatted.setv(text, ap);
- va_end(ap);
-
- MessageBoxA(NULL, formatted.cstr(), "Android SDK Manager", MB_OK | MB_ICONINFORMATION);
-}
-
-static void displayLastError(const char *description, ...) {
- CString formatted;
- va_list ap;
- va_start(ap, description);
- formatted.setv(description, ap);
- va_end(ap);
-
- DWORD err = GetLastError();
- LPSTR errStr;
- if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | /* dwFlags */
- FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, /* lpSource */
- err, /* dwMessageId */
- 0, /* dwLanguageId */
- (LPSTR)&errStr, /* lpBuffer */
- 0, /* nSize */
- NULL) != 0) { /* va_list args */
- formatted.add("\r\n");
- formatted.add(errStr);
- MessageBox(NULL, formatted.cstr(), "Android SDK Manager - Error", MB_OK | MB_ICONERROR);
- LocalFree(errStr);
- }
-}
-
-// Executes the command line. Does not wait for the program to finish.
-// The return code is from CreateProcess (0 means failure), not the running app.
-static int execNoWait(const char *app, const char *params, const char *workDir) {
- STARTUPINFO startup;
- PROCESS_INFORMATION pinfo;
-
- ZeroMemory(&pinfo, sizeof(pinfo));
-
- ZeroMemory(&startup, sizeof(startup));
- startup.cb = sizeof(startup);
- startup.dwFlags = STARTF_USESHOWWINDOW;
- startup.wShowWindow = SW_HIDE|SW_MINIMIZE;
-
- int ret = CreateProcessA(
- (LPSTR) app, /* program path */
- (LPSTR) params, /* command-line */
- NULL, /* process handle is not inheritable */
- NULL, /* thread handle is not inheritable */
- TRUE, /* yes, inherit some handles */
- CREATE_NO_WINDOW, /* we don't want a console */
- NULL, /* use parent's environment block */
- workDir, /* use parent's starting directory */
- &startup, /* startup info, i.e. std handles */
- &pinfo);
-
- if (ret) {
- CloseHandle(pinfo.hProcess);
- CloseHandle(pinfo.hThread);
- }
-
- return ret;
-}
-
-
-// Executes command, waits for completion and returns exit code.
-// As indicated in MSDN for CreateProcess, callers should double-quote the program name
-// e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2";
-static int execWait(const char *cmd) {
- STARTUPINFO startup;
- PROCESS_INFORMATION pinfo;
-
- ZeroMemory(&pinfo, sizeof(pinfo));
-
- ZeroMemory(&startup, sizeof(startup));
- startup.cb = sizeof(startup);
- startup.dwFlags = STARTF_USESHOWWINDOW;
- startup.wShowWindow = SW_HIDE|SW_MINIMIZE;
-
- int ret = CreateProcessA(
- NULL, /* program path */
- (LPSTR) cmd, /* command-line */
- NULL, /* process handle is not inheritable */
- NULL, /* thread handle is not inheritable */
- TRUE, /* yes, inherit some handles */
- CREATE_NO_WINDOW, /* we don't want a console */
- NULL, /* use parent's environment block */
- NULL, /* use parent's starting directory */
- &startup, /* startup info, i.e. std handles */
- &pinfo);
-
- int result = -1;
- if (ret) {
- WaitForSingleObject(pinfo.hProcess, INFINITE);
-
- DWORD exitCode;
- if (GetExitCodeProcess(pinfo.hProcess, &exitCode)) {
- // this should not return STILL_ACTIVE (259)
- result = exitCode;
- }
- CloseHandle(pinfo.hProcess);
- CloseHandle(pinfo.hThread);
- }
-
- return result;
-}
-
-static bool getModuleDir(CPath *outDir) {
- CHAR programDir[MAX_PATH];
- int ret = GetModuleFileName(NULL, programDir, sizeof(programDir));
- if (ret != 0) {
- // Remove the last segment to keep only the directory.
- int pos = ret - 1;
- while (pos > 0 && programDir[pos] != '\\') {
- --pos;
- }
- outDir->set(programDir, pos);
- return true;
- }
- return false;
-}
-
-// Disable the FS redirection done by WOW64.
-// Because this runs as a 32-bit app, Windows automagically remaps some
-// folder under the hood (e.g. "Programs Files(x86)" is mapped as "Program Files").
-// This prevents the app from correctly searching for java.exe in these folders.
-// The registry is also remapped.
-static PVOID disableWow64FsRedirection() {
-
- // The call we want to make is the following:
- // PVOID oldWow64Value;
- // Wow64DisableWow64FsRedirection(&oldWow64Value);
- // However that method may not exist (e.g. on non-64 systems) so
- // we must not call it directly.
-
- PVOID oldWow64Value = 0;
-
- HMODULE hmod = LoadLibrary("kernel32.dll");
- if (hmod != NULL) {
- FARPROC proc = GetProcAddress(hmod, "Wow64DisableWow64FsRedirection");
- if (proc != NULL) {
- typedef BOOL (WINAPI *disableWow64FuncType)(PVOID *);
- disableWow64FuncType funcPtr = (disableWow64FuncType)proc;
- funcPtr(&oldWow64Value);
- }
-
- FreeLibrary(hmod);
- }
-
- return oldWow64Value;
-}
-
-//Reverts the redirection disabled in disableWow64FsRedirection.
-static void revertWow64FsRedirection(PVOID oldWow64Value) {
-
- // The call we want to make is the following:
- // Wow64RevertWow64FsRedirection(oldWow64Value);
- // However that method may not exist (e.g. on non-64 systems) so
- // we must not call it directly.
-
- HMODULE hmod = LoadLibrary("kernel32.dll");
- if (hmod != NULL) {
- FARPROC proc = GetProcAddress(hmod, "Wow64RevertWow64FsRedirection");
- if (proc != NULL) {
- typedef BOOL (WINAPI *revertWow64FuncType)(PVOID);
- revertWow64FuncType funcPtr = (revertWow64FuncType)proc;
- funcPtr(oldWow64Value);
- }
-
- FreeLibrary(hmod);
- }
-}
-
-
-// =============================
-
-// Search java.exe in the path
-static bool findJavaInEnvPath(CPath *outJavaPath) {
- SetLastError(0);
- const char* envPath = getenv("PATH");
- if (!envPath) return false;
-
- CArray<CString> *paths = CString(envPath).split(';');
- for(int i = 0; i < paths->size(); i++) {
- CPath p((*paths)[i].cstr());
- p.addPath("java.exe");
- if (p.fileExists()) {
- // Make sure we can actually run "java -version".
- CString cmd;
- cmd.setf("\"%s\" -version", p.cstr());
- int code = execWait(cmd.cstr());
- if (code == 0) {
- if (gDebug) msgBox("Java found via env path: %s", p.cstr());
- outJavaPath->set(p.cstr());
- delete paths;
- return true;
- }
- }
- }
-
- delete paths;
- return false;
-}
-
-static bool findJavaInRegistry(CPath *outJavaPath) {
- // TODO
- return false;
-}
-
-static bool findJavaInProgramFiles(CPath *outJavaPath) {
- // TODO
- return false;
-}
// Creates a directory named dirLeafName in the TEMP directory.
// Returns the path in outDir on success.