| /* 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 <stdlib.h> |
| #include <errno.h> |
| #include <sys/time.h> |
| |
| #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); |
| } |