1 /*
2 * Copyright (C) 2005 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "misc"
18
19 //
20 // Miscellaneous utility functions.
21 //
22 #include <utils/misc.h>
23 #include <utils/Log.h>
24
25 #include <sys/stat.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <assert.h>
29 #include <stdio.h>
30
31 #if defined(HAVE_PTHREADS)
32 # include <pthread.h>
33 #endif
34
35 #include <utils/Vector.h>
36
37 using namespace android;
38
39 namespace android {
40
41 /*
42 * Like strdup(), but uses C++ "new" operator instead of malloc.
43 */
strdupNew(const char * str)44 char* strdupNew(const char* str)
45 {
46 char* newStr;
47 int len;
48
49 if (str == NULL)
50 return NULL;
51
52 len = strlen(str);
53 newStr = new char[len+1];
54 memcpy(newStr, str, len+1);
55
56 return newStr;
57 }
58
59 /*
60 * Concatenate an argument vector.
61 */
concatArgv(int argc,const char * const argv[])62 char* concatArgv(int argc, const char* const argv[])
63 {
64 char* newStr = NULL;
65 int len, totalLen, posn, idx;
66
67 /*
68 * First, figure out the total length.
69 */
70 totalLen = idx = 0;
71 while (1) {
72 if (idx == argc || argv[idx] == NULL)
73 break;
74 if (idx)
75 totalLen++; // leave a space between args
76 totalLen += strlen(argv[idx]);
77 idx++;
78 }
79
80 /*
81 * Alloc the string.
82 */
83 newStr = new char[totalLen +1];
84 if (newStr == NULL)
85 return NULL;
86
87 /*
88 * Finally, allocate the string and copy data over.
89 */
90 idx = posn = 0;
91 while (1) {
92 if (idx == argc || argv[idx] == NULL)
93 break;
94 if (idx)
95 newStr[posn++] = ' ';
96
97 len = strlen(argv[idx]);
98 memcpy(&newStr[posn], argv[idx], len);
99 posn += len;
100
101 idx++;
102 }
103
104 assert(posn == totalLen);
105 newStr[posn] = '\0';
106
107 return newStr;
108 }
109
110 /*
111 * Count the #of args in an argument vector. Don't count the final NULL.
112 */
countArgv(const char * const argv[])113 int countArgv(const char* const argv[])
114 {
115 int count = 0;
116
117 while (argv[count] != NULL)
118 count++;
119
120 return count;
121 }
122
123
124 #include <stdio.h>
125 /*
126 * Get a file's type.
127 */
getFileType(const char * fileName)128 FileType getFileType(const char* fileName)
129 {
130 struct stat sb;
131
132 if (stat(fileName, &sb) < 0) {
133 if (errno == ENOENT || errno == ENOTDIR)
134 return kFileTypeNonexistent;
135 else {
136 fprintf(stderr, "getFileType got errno=%d on '%s'\n",
137 errno, fileName);
138 return kFileTypeUnknown;
139 }
140 } else {
141 if (S_ISREG(sb.st_mode))
142 return kFileTypeRegular;
143 else if (S_ISDIR(sb.st_mode))
144 return kFileTypeDirectory;
145 else if (S_ISCHR(sb.st_mode))
146 return kFileTypeCharDev;
147 else if (S_ISBLK(sb.st_mode))
148 return kFileTypeBlockDev;
149 else if (S_ISFIFO(sb.st_mode))
150 return kFileTypeFifo;
151 #ifdef HAVE_SYMLINKS
152 else if (S_ISLNK(sb.st_mode))
153 return kFileTypeSymlink;
154 else if (S_ISSOCK(sb.st_mode))
155 return kFileTypeSocket;
156 #endif
157 else
158 return kFileTypeUnknown;
159 }
160 }
161
162 /*
163 * Get a file's modification date.
164 */
getFileModDate(const char * fileName)165 time_t getFileModDate(const char* fileName)
166 {
167 struct stat sb;
168
169 if (stat(fileName, &sb) < 0)
170 return (time_t) -1;
171
172 return sb.st_mtime;
173 }
174
175 /*
176 * Round up to the next highest power of 2.
177 *
178 * Found on http://graphics.stanford.edu/~seander/bithacks.html.
179 */
roundUpPower2(unsigned int val)180 unsigned int roundUpPower2(unsigned int val)
181 {
182 val--;
183 val |= val >> 1;
184 val |= val >> 2;
185 val |= val >> 4;
186 val |= val >> 8;
187 val |= val >> 16;
188 val++;
189
190 return val;
191 }
192
193 struct sysprop_change_callback_info {
194 sysprop_change_callback callback;
195 int priority;
196 };
197
198 #if defined(HAVE_PTHREADS)
199 static pthread_mutex_t gSyspropMutex = PTHREAD_MUTEX_INITIALIZER;
200 static Vector<sysprop_change_callback_info>* gSyspropList = NULL;
201 #endif
202
add_sysprop_change_callback(sysprop_change_callback cb,int priority)203 void add_sysprop_change_callback(sysprop_change_callback cb, int priority) {
204 #if defined(HAVE_PTHREADS)
205 pthread_mutex_lock(&gSyspropMutex);
206 if (gSyspropList == NULL) {
207 gSyspropList = new Vector<sysprop_change_callback_info>();
208 }
209 sysprop_change_callback_info info;
210 info.callback = cb;
211 info.priority = priority;
212 bool added = false;
213 for (size_t i=0; i<gSyspropList->size(); i++) {
214 if (priority >= gSyspropList->itemAt(i).priority) {
215 gSyspropList->insertAt(info, i);
216 added = true;
217 break;
218 }
219 }
220 if (!added) {
221 gSyspropList->add(info);
222 }
223 pthread_mutex_unlock(&gSyspropMutex);
224 #endif
225 }
226
report_sysprop_change()227 void report_sysprop_change() {
228 #if defined(HAVE_PTHREADS)
229 pthread_mutex_lock(&gSyspropMutex);
230 Vector<sysprop_change_callback_info> listeners;
231 if (gSyspropList != NULL) {
232 listeners = *gSyspropList;
233 }
234 pthread_mutex_unlock(&gSyspropMutex);
235
236 //ALOGI("Reporting sysprop change to %d listeners", listeners.size());
237 for (size_t i=0; i<listeners.size(); i++) {
238 listeners[i].callback();
239 }
240 #endif
241 }
242
243 }; // namespace android
244