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
prepare(android::String8 & dirPath)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
FileUtil()79 FileUtil::FileUtil()
80 {
81 mBuffer = new char[DEFAULT_BUFFER_SIZE];
82 if (mBuffer == NULL) {
83 // cannot use ASSERT here, just crash
84 abort();
85 }
86 mBufferSize = DEFAULT_BUFFER_SIZE;
87 }
88
~FileUtil()89 FileUtil::~FileUtil()
90 {
91 if (mFile.is_open()) {
92 mFile.close();
93 }
94 delete[] mBuffer;
95 }
96
init(const char * fileName)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
doVprintf(bool fileOnly,int logLevel,const char * fmt,va_list ap)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 abort();
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
doPrintf(const char * fmt,...)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