1/* Copyright (C) 2009 The Android Open Source Project 2** 3** This software is licensed under the terms of the GNU General Public 4** License version 2, as published by the Free Software Foundation, and 5** may be copied, distributed, and modified under those terms. 6** 7** This program is distributed in the hope that it will be useful, 8** but WITHOUT ANY WARRANTY; without even the implied warranty of 9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10** GNU General Public License for more details. 11*/ 12#include "android/user-config.h" 13#include "android/utils/bufprint.h" 14#include "android/utils/debug.h" 15#include "android/utils/system.h" 16#include "android/utils/path.h" 17#include <stdlib.h> 18#include <errno.h> 19#include <sys/time.h> 20 21#define D(...) VERBOSE_PRINT(init,__VA_ARGS__) 22 23#if 0 /* set to 1 for more debugging */ 24# define DD(...) D(__VA_ARGS__) 25#else 26# define DD(...) ((void)0) 27#endif 28 29struct AUserConfig { 30 ABool changed; 31 int windowX; 32 int windowY; 33 uint64_t uuid; 34 char* iniPath; 35}; 36 37/* Name of the user-config file */ 38#define USER_CONFIG_FILE "emulator-user.ini" 39 40#define KEY_WINDOW_X "window.x" 41#define KEY_WINDOW_Y "window.y" 42#define KEY_UUID "uuid" 43 44#define DEFAULT_X 100 45#define DEFAULT_Y 100 46 47/* Create a new AUserConfig object from a given AvdInfo */ 48AUserConfig* 49auserConfig_new( AvdInfo* info ) 50{ 51 AUserConfig* uc; 52 char inAndroidBuild = avdInfo_inAndroidBuild(info); 53 char needUUID = 1; 54 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 55 char* parentPath; 56 IniFile* ini = NULL; 57 58 ANEW0(uc); 59 60 /* If we are in the Android build system, store the configuration 61 * in ~/.android/emulator-user.ini. otherwise, store it in the file 62 * emulator-user.ini in the AVD's content directory. 63 */ 64 if (inAndroidBuild) { 65 p = bufprint_config_file(temp, end, USER_CONFIG_FILE); 66 } else { 67 p = bufprint(temp, end, "%s/%s", avdInfo_getContentPath(info), 68 USER_CONFIG_FILE); 69 } 70 71 /* handle the unexpected */ 72 if (p >= end) { 73 /* Hmmm, something is weird, let's use a temporary file instead */ 74 p = bufprint_temp_file(temp, end, USER_CONFIG_FILE); 75 if (p >= end) { 76 derror("Weird: Cannot create temporary user-config file?"); 77 exit(2); 78 } 79 dwarning("Weird: Content path too long, using temporary user-config."); 80 } 81 82 uc->iniPath = ASTRDUP(temp); 83 DD("looking user-config in: %s", uc->iniPath); 84 85 86 /* ensure that the parent directory exists */ 87 parentPath = path_parent(uc->iniPath, 1); 88 if (parentPath == NULL) { 89 derror("Weird: Can't find parent of user-config file: %s", 90 uc->iniPath); 91 exit(2); 92 } 93 94 if (!path_exists(parentPath)) { 95 if (!inAndroidBuild) { 96 derror("Weird: No content path for this AVD: %s", parentPath); 97 exit(2); 98 } 99 DD("creating missing directory: %s", parentPath); 100 if (path_mkdir_if_needed(parentPath, 0755) < 0) { 101 derror("Using empty user-config, can't create %s: %s", 102 parentPath, strerror(errno)); 103 exit(2); 104 } 105 } 106 107 if (path_exists(uc->iniPath)) { 108 DD("reading user-config file"); 109 ini = iniFile_newFromFile(uc->iniPath); 110 if (ini == NULL) { 111 dwarning("Can't read user-config file: %s\nUsing default values", 112 uc->iniPath); 113 } 114 } 115 116 if (ini != NULL) { 117 uc->windowX = iniFile_getInteger(ini, KEY_WINDOW_X, DEFAULT_X); 118 DD(" found %s = %d", KEY_WINDOW_X, uc->windowX); 119 120 uc->windowY = iniFile_getInteger(ini, KEY_WINDOW_Y, DEFAULT_Y); 121 DD(" found %s = %d", KEY_WINDOW_Y, uc->windowY); 122 123 if (iniFile_getValue(ini, KEY_UUID) != NULL) { 124 uc->uuid = (uint64_t) iniFile_getInt64(ini, KEY_UUID, 0LL); 125 needUUID = 0; 126 DD(" found %s = %lld", KEY_UUID, uc->uuid); 127 } 128 129 iniFile_free(ini); 130 } 131 else { 132 uc->windowX = DEFAULT_X; 133 uc->windowY = DEFAULT_Y; 134 uc->changed = 1; 135 } 136 137 /* Generate a 64-bit UUID if necessary. We simply take the 138 * current time, which avoids any privacy-related value. 139 */ 140 if (needUUID) { 141 struct timeval tm; 142 143 gettimeofday( &tm, NULL ); 144 uc->uuid = (uint64_t)tm.tv_sec*1000 + tm.tv_usec/1000; 145 uc->changed = 1; 146 DD(" Generated UUID = %lld", uc->uuid); 147 } 148 149 return uc; 150} 151 152 153uint64_t 154auserConfig_getUUID( AUserConfig* uconfig ) 155{ 156 return uconfig->uuid; 157} 158 159void 160auserConfig_getWindowPos( AUserConfig* uconfig, int *pX, int *pY ) 161{ 162 *pX = uconfig->windowX; 163 *pY = uconfig->windowY; 164} 165 166 167void 168auserConfig_setWindowPos( AUserConfig* uconfig, int x, int y ) 169{ 170 if (x != uconfig->windowX || y != uconfig->windowY) { 171 uconfig->windowX = x; 172 uconfig->windowY = y; 173 uconfig->changed = 1; 174 } 175} 176 177/* Save the user configuration back to the content directory. 178 * Should be used in an atexit() handler */ 179void 180auserConfig_save( AUserConfig* uconfig ) 181{ 182 IniFile* ini; 183 char temp[256]; 184 185 if (uconfig->changed == 0) { 186 D("User-config was not changed."); 187 return; 188 } 189 190 bufprint(temp, temp+sizeof(temp), 191 "%s = %d\n" 192 "%s = %d\n" 193 "%s = %lld\n", 194 KEY_WINDOW_X, uconfig->windowX, 195 KEY_WINDOW_Y, uconfig->windowY, 196 KEY_UUID, uconfig->uuid ); 197 198 DD("Generated user-config file:\n%s", temp); 199 200 ini = iniFile_newFromMemory(temp, uconfig->iniPath); 201 if (ini == NULL) { 202 D("Weird: can't create user-config iniFile?"); 203 return; 204 } 205 if (iniFile_saveToFile(ini, uconfig->iniPath) < 0) { 206 dwarning("could not save user configuration: %s: %s", 207 uconfig->iniPath, strerror(errno)); 208 } else { 209 D("User configuration saved to %s", uconfig->iniPath); 210 } 211 iniFile_free(ini); 212} 213