int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { gDebug = (getenv("ANDROID_SDKMAN_DEBUG") != NULL); PVOID oldWow64Value = disableWow64FsRedirection(); CPath javaPath; if (!findJavaInEnvPath(&javaPath) && !findJavaInRegistry(&javaPath) && !findJavaInProgramFiles(&javaPath)) { msgBox("Failed to find Java on your system. Please reinstall it."); return 2; } _ASSERT(!javaPath.isEmpty()); revertWow64FsRedirection(oldWow64Value); // For debugging it's convenient to override the tools directory location CPath toolsDir(getenv("ANDROID_SDKMAN_TOOLS_DIR")); if (toolsDir.isEmpty()) { if (!getModuleDir(&toolsDir)) { displayLastError("Failed to get program's filename: "); return 1; } } _ASSERT(!toolsDir.isEmpty()); CPath tmpDir; if (!mkTempDir("temp-android-tool", &tmpDir)) { return 1; } _ASSERT(!tmpDir.isEmpty()); if (!mkDirs(tmpDir.cstr(), sMkDirList)) { return 1; } if (!copyFiles(toolsDir.cstr(), tmpDir.cstr(), sFilesToCopy)) { return 1; } if (!execSdkManager(javaPath.cstr(), toolsDir.cstr(), tmpDir.cstr(), lpCmdLine)) { displayLastError("Failed to start SDK Manager: "); return 1; } return 0; }
// Check whether we can find $PATH/java.exe. // inOutPath should be the directory where we're looking at. // In output, it will be the java path we tested. // Returns the java version integer found (e.g. 1006 for 1.6). // Return 0 in case of error. static int checkPath(CPath *inOutPath) { inOutPath->addPath("java.exe"); int result = 0; PVOID oldWow64Value = disableWow64FsRedirection(); if (inOutPath->fileExists()) { // Run java -version // Reject the version if it's not at least our current minimum. if (!getJavaVersion(*inOutPath, NULL /*versionStr*/, &result)) { result = 0; } } revertWow64FsRedirection(oldWow64Value); return result; }
int findJavaInProgramFiles(CPath *outJavaPath) { // Check the C:\\Program Files (x86) directory // With WOW64 fs redirection in place by default, we should get the x86 // version on a 64-bit OS since this app is a 32-bit itself. bool result = false; int version = MIN_JAVA_VERSION - 1; result |= checkProgramFiles(outJavaPath, &version); // Check the real sysinfo state (not the one hidden by WOW64) for x86 SYSTEM_INFO sysInfo; GetNativeSystemInfo(&sysInfo); if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { // On a 64-bit OS, try again by disabling the fs redirection so // that we can try the real C:\\Program Files directory. PVOID oldWow64Value = disableWow64FsRedirection(); result |= checkProgramFiles(outJavaPath, &version); revertWow64FsRedirection(oldWow64Value); } return result ? version : 0; }
static bool execSdkManager(const char *javaPath, const char *toolsDir, const char *tmpDir, const char *lpCmdLine) { SetLastError(0); // Which java binary to call. // The default is to use java.exe to automatically dump stdout in // the parent console. CPath javaExecPath(javaPath); // Attach to the parent console, if there's one. if (AttachConsole(-1) == 0) { // This can fail with ERROR_ACCESS_DENIED if the process is already // attached to the parent console. That means there's a console so // we want to keep invoking java.exe to get stdout into it. // // This also fails if there is no parent console, in which // it means this was invoked not from a shell. It's a good // signal we don't want a new console to show up so we'll // switch to javaw.exe instead, if available. if (GetLastError() != ERROR_ACCESS_DENIED) { SetLastError(0); javaExecPath.replaceName("java.exe", "javaw.exe"); // Only accept it if we can actually find the exec PVOID oldWow64Value = disableWow64FsRedirection(); if (!javaExecPath.fileExists()) { javaExecPath.set(javaPath); } revertWow64FsRedirection(&oldWow64Value); } } // Check whether the underlying system is x86 or x86_64. // We use GetSystemInfo which will see the one masqueraded by Wow64. // (to get the real info, we would use GetNativeSystemInfo instead.) SYSTEM_INFO sysInfo; GetSystemInfo(&sysInfo); CString arch("x86"); if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { arch.set("x86_64"); } else if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) { // Skip this. We'll just assume x86 and let it fail later. // Keep this line for debugging purposes: // displayLastError("Unknown Processor Architecture: %d", sysInfo.wProcessorArchitecture); } // Now build the command line. // Note that we pass the absolute javaExecPath both to CreateProcess (via execNoWait) // and we set it as argv[0] in the command line just for the show. // Important: for the classpath to be able to contain "lib\\sdkmanager.jar", etc., // we need to set the toolsDir as the *temp* directory in execNoWait. // It's important to not use toolsDir otherwise it would lock that diretory. CString cmdLine; cmdLine.setf("\"%s\" " // javaPath "-Dcom.android.sdkmanager.toolsdir=\"%s\" " // toolsDir "-Dcom.android.sdkmanager.workdir=\"%s\" " // workDir==toolsdir "-classpath \"lib\\sdkmanager.jar;lib\\swtmenubar.jar;lib\\%s\\swt.jar\" " // arch "com.android.sdkmanager.Main " "%s", // extra parameters javaExecPath.baseName(), toolsDir, tmpDir, arch.cstr(), lpCmdLine); // Tip: to connect the Java debugging to a running process, add this to the Java command line: // "-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000" if (gDebug) msgBox("Executing: %s", cmdLine.cstr()); if (!execNoWait(javaExecPath.cstr(), cmdLine.cstr(), tmpDir)) { displayLastError("Failed to run %s", cmdLine.cstr()); return false; } return true; }