/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * "win_android.exe", for Windows only. Replaces the previous android.bat. * In the final SDK, this is what becomes tools\android.exe and it runs * the UI for the SDK Manager or the AVD Manager. * * Implementation details: * - We don't have access to ATL or MFC. * - We don't want to pull in things like STL. * - No Unicode/MBCS support for now. */ #ifdef _WIN32 #include "utils.h" #include "find_java.h" // A NULL-terminated list of directory to create in the temp folder. static const char * sMkDirList[] = { "lib", "lib\\x86", "lib\\x86_64", NULL, }; // A NULL-terminated list of file patterns to copy in the temp folder. // The folders must be listed in sMkDirList static const char * sFilesToCopy[] = { "lib\\x86\\swt.jar", "lib\\x86_64\\swt.jar", "lib\\androidprefs.jar", "lib\\org.eclipse.*", "lib\\sdk*", "lib\\common.jar", "lib\\commons-compress*", "lib\\swtmenubar.jar", "lib\\commons-logging*", "lib\\commons-codec*", "lib\\httpclient*", "lib\\httpcore*", "lib\\httpmime*", NULL, }; // Creates a directory named dirLeafName in the TEMP directory. // Returns the path in outDir on success. static bool mkTempDir(const char *dirLeafName, CPath *outDir) { SetLastError(0); char tempPath[MAX_PATH + 1] = ""; DWORD len = GetTempPathA(MAX_PATH, tempPath); if (len > 0 && len <= MAX_PATH) { _ASSERT(tempPath[len-1] == '\\'); _ASSERT(len + strlen(dirLeafName) < MAX_PATH); if (len + strlen(dirLeafName) >= MAX_PATH) { displayLastError("TEMP path too long to create a temporary directory: %s", tempPath); return false; } strcat(tempPath, dirLeafName); outDir->set(tempPath); if (outDir->dirExists() || CreateDirectoryA(tempPath, NULL /*lpSecurityAttributes*/) != 0) { return true; } } displayLastError("Failed to create a temporary directory: %s", tempPath); return false; } // Creates all the directories from sMkDirList in the specified base tmpDir. static bool mkDirs(const char *tmpDir, const char * dirList[]) { SetLastError(0); for (const char **dir = dirList; *dir != NULL; dir++) { CPath path(tmpDir); path.addPath(*dir); if (!path.dirExists()) { if (!CreateDirectoryA(path.cstr(), NULL /*lpSecurityAttributes*/)) { displayLastError("Failed to create directory: %s", path.cstr()); return false; } } } return true; } static bool copyFiles(const char *toolsDir, const char *tmpDir, const char *globList[]) { SetLastError(0); WIN32_FIND_DATAA srcFindData; WIN32_FIND_DATAA destFindData; for (const char **glob = globList; *glob != NULL; glob++) { CPath globDir = CPath(*glob).dirName(); CPath fullGlob(toolsDir); fullGlob.addPath(*glob); HANDLE srcH = FindFirstFileA(fullGlob.cstr(), &srcFindData); if (srcH == INVALID_HANDLE_VALUE) { displayLastError("Failed to list files: %s", *glob); return false; } do { // Skip directories if ((srcFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { continue; } CPath srcPath(toolsDir); srcPath.addPath(globDir).addPath(srcFindData.cFileName); CPath destPath(tmpDir); destPath.addPath(globDir).addPath(srcFindData.cFileName); // Skip copy if files are likely to not have changed. HANDLE destH = FindFirstFileA(destPath.cstr(), &destFindData); if (destH != INVALID_HANDLE_VALUE) { // Size must be same for us to skip it. if (srcFindData.nFileSizeHigh == destFindData.nFileSizeHigh && srcFindData.nFileSizeLow == destFindData.nFileSizeLow) { // Creation & access times can differ. However if the dest write time // is >= than the source write time, it should be the same file. LARGE_INTEGER srcWriteTime; LARGE_INTEGER dstWriteTime; srcWriteTime.HighPart = srcFindData.ftLastWriteTime.dwHighDateTime; srcWriteTime.LowPart = srcFindData.ftLastWriteTime.dwLowDateTime; dstWriteTime.HighPart = destFindData.ftLastWriteTime.dwHighDateTime; dstWriteTime.LowPart = destFindData.ftLastWriteTime.dwLowDateTime; if (dstWriteTime.QuadPart >= srcWriteTime.QuadPart) { FindClose(destH); continue; } } FindClose(destH); // CopyFile copies some attributes. It's common for tools to be unzipped // as read-only so we need to remove any r-o attribute on existing // files if we want a recopy to succeed. if ((destFindData.dwFileAttributes && FILE_ATTRIBUTE_READONLY) != 0) { SetFileAttributes(destPath.cstr(), destFindData.dwFileAttributes ^ FILE_ATTRIBUTE_READONLY); } } if (!CopyFileA(srcPath.cstr(), destPath.cstr(), false /*bFailIfExists*/)) { FindClose(srcH); displayLastError("Failed to copy file: %s", destPath.cstr()); return false; } } while (FindNextFileA(srcH, &srcFindData) != 0); FindClose(srcH); } return true; } static bool execSdkManager(const char *javaPath, const char *toolsDir, const char *tmpDir, const char *lpCmdLine) { SetLastError(0); CPath javawPath(javaPath); javawPath.replaceName("java.exe", "javaw.exe"); // Only accept it if we can actually find the exec PVOID oldWow64Value = disableWow64FsRedirection(); if (!javawPath.fileExists()) { javawPath.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. // displayLastError("Unknown Processor Architecture: %d", sysInfo.wProcessorArchitecture); // return false; } // Now build the command line. // Note that we pass the absolute javawPath to execNoWait // and the first parameter is 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. // 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" 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 javawPath.baseName(), toolsDir, tmpDir, arch.cstr(), lpCmdLine); if (gDebug) msgBox("Executing: %s", cmdLine.cstr()); if (!execNoWait(javawPath.cstr(), cmdLine.cstr(), tmpDir)) { displayLastError("Failed to run %s", cmdLine.cstr()); return false; } return true; } 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 more convenient to be able 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; } #endif /* _WIN32 */