Home | History | Annotate | Download | only in android
      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 
     29 struct 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 */
     48 AUserConfig*
     49 auserConfig_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 
    153 uint64_t
    154 auserConfig_getUUID( AUserConfig*  uconfig )
    155 {
    156     return uconfig->uuid;
    157 }
    158 
    159 void
    160 auserConfig_getWindowPos( AUserConfig*  uconfig, int  *pX, int  *pY )
    161 {
    162     *pX = uconfig->windowX;
    163     *pY = uconfig->windowY;
    164 }
    165 
    166 
    167 void
    168 auserConfig_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 */
    179 void
    180 auserConfig_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