Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 #include <time.h>
     17 #include <sys/stat.h>
     18 #include <sys/types.h>
     19 #include <errno.h>
     20 
     21 #include "Log.h"
     22 #include "Settings.h"
     23 #include "StringUtil.h"
     24 #include "FileUtil.h"
     25 
     26 
     27 // This class is used by Log. So we cannot use LOG? macros here.
     28 #define _LOGD_(x...) do { fprintf(stderr, x); fprintf(stderr, "\n"); } while(0)
     29 
     30 // reported generated under reports/YYYY_MM_DD_HH_MM_SS dir
     31 const char reportTopDir[] = "reports";
     32 android::String8 FileUtil::mDirPath;
     33 
     34 bool FileUtil::prepare(android::String8& dirPath)
     35 {
     36     if (mDirPath.length() != 0) {
     37         dirPath = mDirPath;
     38         _LOGD_("mDirPath %s", mDirPath.string());
     39         return true;
     40     }
     41 
     42     time_t timeNow = time(NULL);
     43     if (timeNow == ((time_t)-1)) {
     44         _LOGD_("time error");
     45        return false;
     46     }
     47     // tm is allocated in static buffer, and should not be freed.
     48     struct tm* tm = localtime(&timeNow);
     49     if (tm == NULL) {
     50         _LOGD_("localtime error");
     51         return false;
     52     }
     53     int result = mkdir(reportTopDir, S_IRWXU);
     54     if ((result == -1) && (errno != EEXIST)) {
     55         _LOGD_("mkdir of topdir failed, error %d", errno);
     56         return false;
     57     }
     58     android::String8 reportTime;
     59     if (reportTime.appendFormat("%04d_%02d_%02d_%02d_%02d_%02d", tm->tm_year + 1900,
     60                 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec) != 0) {
     61             return false;
     62     }
     63     Settings::Instance()->addSetting(Settings::EREPORT_TIME, reportTime);
     64     android::String8 path;
     65     if (path.appendFormat("%s/%s", reportTopDir, reportTime.string()) != 0) {
     66         return false;
     67     }
     68     result = mkdir(path.string(), S_IRWXU);
     69     if ((result == -1) && (errno != EEXIST)) {
     70         _LOGD_("mkdir of report dir failed, error %d", errno);
     71         return false;
     72     }
     73     mDirPath = path;
     74     dirPath = path;
     75 
     76     return true;
     77 }
     78 
     79 FileUtil::FileUtil()
     80 {
     81     mBuffer = new char[DEFAULT_BUFFER_SIZE];
     82     if (mBuffer == NULL) {
     83         // cannot use ASSERT here, just crash
     84         *(char*)0 = 0;
     85     }
     86     mBufferSize = DEFAULT_BUFFER_SIZE;
     87 }
     88 
     89 FileUtil::~FileUtil()
     90 {
     91     if (mFile.is_open()) {
     92         mFile.close();
     93     }
     94     delete[] mBuffer;
     95 }
     96 
     97 bool FileUtil::init(const char* fileName)
     98 {
     99     if (fileName == NULL) {
    100         return true;
    101     }
    102 
    103     mFile.open(fileName, std::ios::out | std::ios::trunc);
    104     if (!mFile.is_open()) {
    105             return false;
    106         }
    107     return true;
    108 }
    109 
    110 bool FileUtil::doVprintf(bool fileOnly, int logLevel, const char *fmt, va_list ap)
    111 {
    112     // prevent messed up log in multi-thread env. Still multi-line logs can be messed up.
    113     android::Mutex::Autolock lock(mWriteLock);
    114     while (1) {
    115         int start = 0;
    116         if (logLevel != -1) {
    117             mBuffer[0] = '0' + logLevel;
    118             mBuffer[1] = '>';
    119             start = 2;
    120         }
    121         int size;
    122         size = vsnprintf(mBuffer + start, mBufferSize - start - 2, fmt, ap); // 2 for \n\0
    123         if (size < 0) {
    124             fprintf(stderr, "FileUtil::vprintf failed");
    125             return false;
    126         }
    127         if ((size + start + 2) > mBufferSize) {
    128             //default buffer does not fit, increase buffer size and retry
    129             delete[] mBuffer;
    130             mBuffer = new char[2 * size];
    131             if (mBuffer == NULL) {
    132                 // cannot use ASSERT here, just crash
    133                 *(char*)0 = 0;
    134             }
    135             mBufferSize = 2 * size;
    136             // re-try
    137             continue;
    138         }
    139         size += start;
    140         mBuffer[size] = '\n';
    141         size++;
    142         mBuffer[size] = 0;
    143 
    144         if (!fileOnly) {
    145             fprintf(stdout, "%s", mBuffer);
    146         }
    147         if (mFile.is_open()) {
    148             mFile<<mBuffer;
    149         }
    150         return true;
    151     }
    152 }
    153 
    154 bool FileUtil::doPrintf(const char* fmt, ...)
    155 {
    156     va_list ap;
    157     va_start(ap, fmt);
    158     bool result = doVprintf(false, -1, fmt, ap);
    159     va_end(ap);
    160     return result;
    161 }
    162