| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| #include <time.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <errno.h> |
| |
| #include "Log.h" |
| #include "Settings.h" |
| #include "StringUtil.h" |
| #include "FileUtil.h" |
| |
| |
| // This class is used by Log. So we cannot use LOG? macros here. |
| #define _LOGD_(x...) do { fprintf(stderr, x); fprintf(stderr, "\n"); } while(0) |
| |
| // reported generated under reports/YYYY_MM_DD_HH_MM_SS dir |
| const char reportTopDir[] = "reports"; |
| android::String8 FileUtil::mDirPath; |
| |
| bool FileUtil::prepare(android::String8& dirPath) |
| { |
| if (mDirPath.length() != 0) { |
| dirPath = mDirPath; |
| _LOGD_("mDirPath %s", mDirPath.string()); |
| return true; |
| } |
| |
| time_t timeNow = time(NULL); |
| if (timeNow == ((time_t)-1)) { |
| _LOGD_("time error"); |
| return false; |
| } |
| // tm is allocated in static buffer, and should not be freed. |
| struct tm* tm = localtime(&timeNow); |
| if (tm == NULL) { |
| _LOGD_("localtime error"); |
| return false; |
| } |
| int result = mkdir(reportTopDir, S_IRWXU); |
| if ((result == -1) && (errno != EEXIST)) { |
| _LOGD_("mkdir of topdir failed, error %d", errno); |
| return false; |
| } |
| android::String8 reportTime; |
| if (reportTime.appendFormat("%04d_%02d_%02d_%02d_%02d_%02d", tm->tm_year + 1900, |
| tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec) != 0) { |
| return false; |
| } |
| Settings::Instance()->addSetting(Settings::EREPORT_TIME, reportTime); |
| android::String8 path; |
| if (path.appendFormat("%s/%s", reportTopDir, reportTime.string()) != 0) { |
| return false; |
| } |
| result = mkdir(path.string(), S_IRWXU); |
| if ((result == -1) && (errno != EEXIST)) { |
| _LOGD_("mkdir of report dir failed, error %d", errno); |
| return false; |
| } |
| mDirPath = path; |
| dirPath = path; |
| |
| return true; |
| } |
| |
| FileUtil::FileUtil() |
| { |
| mBuffer = new char[DEFAULT_BUFFER_SIZE]; |
| if (mBuffer == NULL) { |
| // cannot use ASSERT here, just crash |
| *(char*)0 = 0; |
| } |
| mBufferSize = DEFAULT_BUFFER_SIZE; |
| } |
| |
| FileUtil::~FileUtil() |
| { |
| if (mFile.is_open()) { |
| mFile.close(); |
| } |
| delete[] mBuffer; |
| } |
| |
| bool FileUtil::init(const char* fileName) |
| { |
| if (fileName == NULL) { |
| return true; |
| } |
| |
| mFile.open(fileName, std::ios::out | std::ios::trunc); |
| if (!mFile.is_open()) { |
| return false; |
| } |
| return true; |
| } |
| |
| bool FileUtil::doVprintf(bool fileOnly, int logLevel, const char *fmt, va_list ap) |
| { |
| // prevent messed up log in multi-thread env. Still multi-line logs can be messed up. |
| android::Mutex::Autolock lock(mWriteLock); |
| while (1) { |
| int start = 0; |
| if (logLevel != -1) { |
| mBuffer[0] = '0' + logLevel; |
| mBuffer[1] = '>'; |
| start = 2; |
| } |
| int size; |
| size = vsnprintf(mBuffer + start, mBufferSize - start - 2, fmt, ap); // 2 for \n\0 |
| if (size < 0) { |
| fprintf(stderr, "FileUtil::vprintf failed"); |
| return false; |
| } |
| if ((size + start + 2) > mBufferSize) { |
| //default buffer does not fit, increase buffer size and retry |
| delete[] mBuffer; |
| mBuffer = new char[2 * size]; |
| if (mBuffer == NULL) { |
| // cannot use ASSERT here, just crash |
| *(char*)0 = 0; |
| } |
| mBufferSize = 2 * size; |
| // re-try |
| continue; |
| } |
| size += start; |
| mBuffer[size] = '\n'; |
| size++; |
| mBuffer[size] = 0; |
| |
| if (!fileOnly) { |
| fprintf(stdout, "%s", mBuffer); |
| } |
| if (mFile.is_open()) { |
| mFile<<mBuffer; |
| } |
| return true; |
| } |
| } |
| |
| bool FileUtil::doPrintf(const char* fmt, ...) |
| { |
| va_list ap; |
| va_start(ap, fmt); |
| bool result = doVprintf(false, -1, fmt, ap); |
| va_end(ap); |
| return result; |
| } |