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 37using namespace android; 38 39namespace android { 40 41/* 42 * Like strdup(), but uses C++ "new" operator instead of malloc. 43 */ 44char* 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 */ 62char* 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 */ 113int 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 */ 128FileType 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 */ 165time_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 */ 180unsigned 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 193struct sysprop_change_callback_info { 194 sysprop_change_callback callback; 195 int priority; 196}; 197 198#if defined(HAVE_PTHREADS) 199static pthread_mutex_t gSyspropMutex = PTHREAD_MUTEX_INITIALIZER; 200static Vector<sysprop_change_callback_info>* gSyspropList = NULL; 201#endif 202 203void 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 227void 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