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