/* Copyright (C) 2009 The Android Open Source Project ** ** This software is licensed under the terms of the GNU General Public ** License version 2, as published by the Free Software Foundation, and ** may be copied, distributed, and modified under those terms. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. */ #include "android/user-config.h" #include "android/utils/bufprint.h" #include "android/utils/debug.h" #include "android/utils/system.h" #include "android/utils/path.h" #include #include #include #define D(...) VERBOSE_PRINT(init,__VA_ARGS__) #if 0 /* set to 1 for more debugging */ # define DD(...) D(__VA_ARGS__) #else # define DD(...) ((void)0) #endif struct AUserConfig { ABool changed; int windowX; int windowY; uint64_t uuid; char* iniPath; }; /* Name of the user-config file */ #define USER_CONFIG_FILE "emulator-user.ini" #define KEY_WINDOW_X "window.x" #define KEY_WINDOW_Y "window.y" #define KEY_UUID "uuid" #define DEFAULT_X 100 #define DEFAULT_Y 100 /* Create a new AUserConfig object from a given AvdInfo */ AUserConfig* auserConfig_new( AvdInfo* info ) { AUserConfig* uc; char inAndroidBuild = avdInfo_inAndroidBuild(info); char needUUID = 1; char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); char* parentPath; IniFile* ini = NULL; ANEW0(uc); /* If we are in the Android build system, store the configuration * in ~/.android/emulator-user.ini. otherwise, store it in the file * emulator-user.ini in the AVD's content directory. */ if (inAndroidBuild) { p = bufprint_config_file(temp, end, USER_CONFIG_FILE); } else { p = bufprint(temp, end, "%s/%s", avdInfo_getContentPath(info), USER_CONFIG_FILE); } /* handle the unexpected */ if (p >= end) { /* Hmmm, something is weird, let's use a temporary file instead */ p = bufprint_temp_file(temp, end, USER_CONFIG_FILE); if (p >= end) { derror("Weird: Cannot create temporary user-config file?"); exit(2); } dwarning("Weird: Content path too long, using temporary user-config."); } uc->iniPath = ASTRDUP(temp); DD("looking user-config in: %s", uc->iniPath); /* ensure that the parent directory exists */ parentPath = path_parent(uc->iniPath, 1); if (parentPath == NULL) { derror("Weird: Can't find parent of user-config file: %s", uc->iniPath); exit(2); } if (!path_exists(parentPath)) { if (!inAndroidBuild) { derror("Weird: No content path for this AVD: %s", parentPath); exit(2); } DD("creating missing directory: %s", parentPath); if (path_mkdir_if_needed(parentPath, 0755) < 0) { derror("Using empty user-config, can't create %s: %s", parentPath, strerror(errno)); exit(2); } } if (path_exists(uc->iniPath)) { DD("reading user-config file"); ini = iniFile_newFromFile(uc->iniPath); if (ini == NULL) { dwarning("Can't read user-config file: %s\nUsing default values", uc->iniPath); } } if (ini != NULL) { uc->windowX = iniFile_getInteger(ini, KEY_WINDOW_X, DEFAULT_X); DD(" found %s = %d", KEY_WINDOW_X, uc->windowX); uc->windowY = iniFile_getInteger(ini, KEY_WINDOW_Y, DEFAULT_Y); DD(" found %s = %d", KEY_WINDOW_Y, uc->windowY); if (iniFile_getValue(ini, KEY_UUID) != NULL) { uc->uuid = (uint64_t) iniFile_getInt64(ini, KEY_UUID, 0LL); needUUID = 0; DD(" found %s = %lld", KEY_UUID, uc->uuid); } iniFile_free(ini); } else { uc->windowX = DEFAULT_X; uc->windowY = DEFAULT_Y; uc->changed = 1; } /* Generate a 64-bit UUID if necessary. We simply take the * current time, which avoids any privacy-related value. */ if (needUUID) { struct timeval tm; gettimeofday( &tm, NULL ); uc->uuid = (uint64_t)tm.tv_sec*1000 + tm.tv_usec/1000; uc->changed = 1; DD(" Generated UUID = %lld", uc->uuid); } return uc; } uint64_t auserConfig_getUUID( AUserConfig* uconfig ) { return uconfig->uuid; } void auserConfig_getWindowPos( AUserConfig* uconfig, int *pX, int *pY ) { *pX = uconfig->windowX; *pY = uconfig->windowY; } void auserConfig_setWindowPos( AUserConfig* uconfig, int x, int y ) { if (x != uconfig->windowX || y != uconfig->windowY) { uconfig->windowX = x; uconfig->windowY = y; uconfig->changed = 1; } } /* Save the user configuration back to the content directory. * Should be used in an atexit() handler */ void auserConfig_save( AUserConfig* uconfig ) { IniFile* ini; char temp[256]; if (uconfig->changed == 0) { D("User-config was not changed."); return; } bufprint(temp, temp+sizeof(temp), "%s = %d\n" "%s = %d\n" "%s = %lld\n", KEY_WINDOW_X, uconfig->windowX, KEY_WINDOW_Y, uconfig->windowY, KEY_UUID, uconfig->uuid ); DD("Generated user-config file:\n%s", temp); ini = iniFile_newFromMemory(temp, uconfig->iniPath); if (ini == NULL) { D("Weird: can't create user-config iniFile?"); return; } if (iniFile_saveToFile(ini, uconfig->iniPath) < 0) { dwarning("could not save user configuration: %s: %s", uconfig->iniPath, strerror(errno)); } else { D("User configuration saved to %s", uconfig->iniPath); } iniFile_free(ini); }