Merge "Remove libmincrypt."
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index a856672..f5d13c3 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1025,50 +1025,40 @@
#endif /* !defined(_WIN32) */
}
-static bool check_wait_for_device_syntax(const char* service) {
- // TODO: when we have libc++ for Windows, use a regular expression instead.
- // wait-for-((any|local|usb)-)?(bootloader|device|recovery|sideload)
-
- char type[20 + 1]; // sscanf's %20[...] doesn't include the NUL.
- char state[20 + 1];
- int length = 0;
- if (sscanf(service, "wait-for-%20[a-z]-%20[a-z]%n", type, state, &length) < 2 ||
- length != static_cast<int>(strlen(service))) {
+static bool wait_for_device(const char* service, TransportType t, const char* serial) {
+ std::vector<std::string> components = android::base::Split(service, "-");
+ if (components.size() < 3 || components.size() > 4) {
fprintf(stderr, "adb: couldn't parse 'wait-for' command: %s\n", service);
return false;
}
- if (strcmp(type, "any") != 0 && strcmp(type, "local") != 0 && strcmp(type, "usb") != 0) {
- fprintf(stderr, "adb: unknown type %s; expected 'any', 'local', or 'usb'\n", type);
- return false;
- }
- if (strcmp(state, "bootloader") != 0 && strcmp(state, "device") != 0 &&
- strcmp(state, "recovery") != 0 && strcmp(state, "sideload") != 0) {
- fprintf(stderr, "adb: unknown state %s; "
- "expected 'bootloader', 'device', 'recovery', or 'sideload'\n", state);
- return false;
- }
- return true;
-}
-
-static bool wait_for_device(const char* service, TransportType t, const char* serial) {
// Was the caller vague about what they'd like us to wait for?
// If so, check they weren't more specific in their choice of transport type.
- if (strcmp(service, "wait-for-device") == 0) {
+ if (components.size() == 3) {
+ auto it = components.begin() + 2;
if (t == kTransportUsb) {
- service = "wait-for-usb-device";
+ components.insert(it, "usb");
} else if (t == kTransportLocal) {
- service = "wait-for-local-device";
+ components.insert(it, "local");
} else {
- service = "wait-for-any-device";
+ components.insert(it, "any");
}
- }
-
- if (!check_wait_for_device_syntax(service)) {
+ } else if (components[2] != "any" && components[2] != "local" && components[2] != "usb") {
+ fprintf(stderr, "adb: unknown type %s; expected 'any', 'local', or 'usb'\n",
+ components[2].c_str());
return false;
}
- std::string cmd = format_host_command(service, t, serial);
+ if (components[3] != "any" && components[3] != "bootloader" && components[3] != "device" &&
+ components[3] != "recovery" && components[3] != "sideload") {
+ fprintf(stderr,
+ "adb: unknown state %s; "
+ "expected 'any', 'bootloader', 'device', 'recovery', or 'sideload'\n",
+ components[3].c_str());
+ return false;
+ }
+
+ std::string cmd = format_host_command(android::base::Join(components, "-").c_str(), t, serial);
return adb_command(cmd);
}
@@ -1114,7 +1104,7 @@
TransportType type;
const char* serial;
adb_get_transport(&type, &serial);
- return wait_for_device("wait-for-device", type, serial);
+ return wait_for_device("wait-for-any", type, serial);
}
// Connects to the device "shell" service with |command| and prints the
diff --git a/adb/services.cpp b/adb/services.cpp
index d5e963b..67e8e41 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -370,7 +370,7 @@
std::string error = "unknown error";
const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : NULL;
atransport* t = acquire_one_transport(sinfo->transport_type, serial, &is_ambiguous, &error);
- if (t != nullptr && t->connection_state == sinfo->state) {
+ if (t != nullptr && (sinfo->state == kCsAny || sinfo->state == t->connection_state)) {
SendOkay(fd);
break;
} else if (!is_ambiguous) {
@@ -534,6 +534,8 @@
sinfo->state = kCsSideload;
} else if (!strcmp(name, "-bootloader")) {
sinfo->state = kCsBootloader;
+ } else if (!strcmp(name, "-any")) {
+ sinfo->state = kCsAny;
} else {
return nullptr;
}
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 4b1e016..b3e65cb 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -635,11 +635,18 @@
}
encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
} else {
- ERROR("Failed to mount an un-encryptable or wiped partition on"
- "%s at %s options: %s error: %s\n",
- fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
- fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
- ++error_count;
+ if (fs_mgr_is_nofail(&fstab->recs[attempted_idx])) {
+ ERROR("Ignoring failure to mount an un-encryptable or wiped partition on"
+ "%s at %s options: %s error: %s\n",
+ fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+ fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
+ } else {
+ ERROR("Failed to mount an un-encryptable or wiped partition on"
+ "%s at %s options: %s error: %s\n",
+ fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+ fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
+ ++error_count;
+ }
continue;
}
}
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index cf35b3f..5b92db7 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -75,6 +75,7 @@
{ "notrim", MF_NOTRIM },
{ "formattable", MF_FORMATTABLE },
{ "slotselect", MF_SLOTSELECT },
+ { "nofail", MF_NOFAIL },
{ "defaults", 0 },
{ 0, 0 },
};
@@ -491,3 +492,8 @@
{
return fstab->fs_mgr_flags & MF_SLOTSELECT;
}
+
+int fs_mgr_is_nofail(struct fstab_rec *fstab)
+{
+ return fstab->fs_mgr_flags & MF_NOFAIL;
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index ba0e097..775f36d 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -82,6 +82,7 @@
#define MF_FILEENCRYPTION 0x2000
#define MF_FORMATTABLE 0x4000
#define MF_SLOTSELECT 0x8000
+#define MF_NOFAIL 0x40000
#define DM_BUF_SIZE 4096
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 27fccf7..c5e1f32 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -105,6 +105,7 @@
int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
int fs_mgr_is_notrim(struct fstab_rec *fstab);
int fs_mgr_is_formattable(struct fstab_rec *fstab);
+int fs_mgr_is_nofail(struct fstab_rec *fstab);
int fs_mgr_swapon_all(struct fstab *fstab);
int fs_mgr_do_format(struct fstab_rec *fstab);
diff --git a/init/init.cpp b/init/init.cpp
index 9b7d108..78c33d5 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -139,59 +139,19 @@
});
}
-static void msg_start(const std::string& name)
-{
- Service* svc = nullptr;
- std::vector<std::string> vargs;
-
- size_t colon_pos = name.find(':');
- if (colon_pos == std::string::npos) {
- svc = ServiceManager::GetInstance().FindServiceByName(name);
- } else {
- std::string service_name(name.substr(0, colon_pos));
- std::string args(name.substr(colon_pos + 1));
- vargs = android::base::Split(args, " ");
-
- svc = ServiceManager::GetInstance().FindServiceByName(service_name);
- }
-
- if (svc) {
- svc->Start(vargs);
- } else {
- ERROR("no such service '%s'\n", name.c_str());
- }
-}
-
-static void msg_stop(const std::string& name)
-{
+void handle_control_message(const std::string& msg, const std::string& name) {
Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
-
- if (svc) {
- svc->Stop();
- } else {
+ if (svc == nullptr) {
ERROR("no such service '%s'\n", name.c_str());
+ return;
}
-}
-static void msg_restart(const std::string& name)
-{
- Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
-
- if (svc) {
- svc->Restart();
- } else {
- ERROR("no such service '%s'\n", name.c_str());
- }
-}
-
-void handle_control_message(const std::string& msg, const std::string& arg)
-{
if (msg == "start") {
- msg_start(arg);
+ svc->Start();
} else if (msg == "stop") {
- msg_stop(arg);
+ svc->Stop();
} else if (msg == "restart") {
- msg_restart(arg);
+ svc->Restart();
} else {
ERROR("unknown control msg '%s'\n", msg.c_str());
}
diff --git a/init/service.cpp b/init/service.cpp
index e509f46..f5b8b00 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -316,7 +316,7 @@
return (this->*handler)(args, err);
}
-bool Service::Start(const std::vector<std::string>& dynamic_args) {
+bool Service::Start() {
// Starting a service removes it from the disabled or reset state and
// immediately takes it out of the restarting state if it was in there.
flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
@@ -352,13 +352,6 @@
return false;
}
- if ((!(flags_ & SVC_ONESHOT)) && !dynamic_args.empty()) {
- ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
- args_[0].c_str());
- flags_ |= SVC_DISABLED;
- return false;
- }
-
std::string scon;
if (!seclabel_.empty()) {
scon = seclabel_;
@@ -480,9 +473,6 @@
for (const auto& s : args_) {
strs.push_back(const_cast<char*>(s.c_str()));
}
- for (const auto& s : dynamic_args) {
- strs.push_back(const_cast<char*>(s.c_str()));
- }
strs.push_back(nullptr);
if (execve(args_[0].c_str(), (char**) &strs[0], (char**) ENV) < 0) {
ERROR("cannot execve('%s'): %s\n", args_[0].c_str(), strerror(errno));
@@ -511,11 +501,6 @@
return true;
}
-bool Service::Start() {
- const std::vector<std::string> null_dynamic_args;
- return Start(null_dynamic_args);
-}
-
bool Service::StartIfNotDisabled() {
if (!(flags_ & SVC_DISABLED)) {
return Start();
diff --git a/init/service.h b/init/service.h
index b003ca0..d6ce664 100644
--- a/init/service.h
+++ b/init/service.h
@@ -76,7 +76,6 @@
const std::string& seclabel, const std::vector<std::string>& args);
bool HandleLine(const std::vector<std::string>& args, std::string* err);
- bool Start(const std::vector<std::string>& dynamic_args);
bool Start();
bool StartIfNotDisabled();
bool Enable();
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index e65469a..52f49cc 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -27,6 +27,7 @@
#include <android-base/file.h>
#include <android-base/strings.h>
+#include <cutils/properties.h>
#include <cutils/sched_policy.h>
#include <cutils/sockets.h>
#include <log/event_tag_map.h>
@@ -278,66 +279,68 @@
fprintf(stderr,"Usage: %s [options] [filterspecs]\n", cmd);
fprintf(stderr, "options include:\n"
- " -s Set default filter to silent.\n"
- " Like specifying filterspec '*:S'\n"
- " -f <filename> Log to file. Default is stdout\n"
- " --file=<filename>\n"
- " -r <kbytes> Rotate log every kbytes. Requires -f\n"
- " --rotate-kbytes=<kbytes>\n"
- " -n <count> Sets max number of rotated logs to <count>, default 4\n"
- " --rotate-count=<count>\n"
- " -v <format> Sets the log print format, where <format> is:\n"
- " --format=<format>\n"
- " brief color epoch long monotonic printable process raw\n"
- " tag thread threadtime time uid usec UTC year zone\n\n"
- " -D print dividers between each log buffer\n"
- " --dividers\n"
- " -c clear (flush) the entire log and exit\n"
- " --clear\n"
- " -d dump the log and then exit (don't block)\n"
- " -e <expr> only print lines where the log message matches <expr>\n"
- " --regex <expr> where <expr> is a regular expression\n"
- " -m <count> quit after printing <count> lines. This is meant to be\n"
- " --max-count=<count> paired with --regex, but will work on its own.\n"
- " --print paired with --regex and --max-count to let content bypass\n"
+ " -s Set default filter to silent. Equivalent to filterspec '*:S'\n"
+ " -f <file>, --file=<file> Log to file. Default is stdout\n"
+ " -r <kbytes>, --rotate-kbytes=<kbytes> Rotate log every kbytes. Requires -f\n"
+ " option. Permits property expansion.\n"
+ " -n <count>, --rotate-count=<count> Sets max number of rotated logs to\n"
+ " <count>, default 4. Permits property expansion.\n"
+ " -v <format>, --format=<format>\n"
+ " Sets the log print format, where <format> is:\n"
+ " brief color epoch long monotonic printable process raw\n"
+ " tag thread threadtime time uid usec UTC year zone\n"
+ " -D, --dividers Print dividers between each log buffer\n"
+ " -c, --clear Clear (flush) the entire log and exit\n"
+ " -d Dump the log and then exit (don't block)\n"
+ " -e <expr>, --regex=<expr>\n"
+ " Only print lines where the log message matches <expr>\n"
+ " where <expr> is a regular expression\n"
+ // Leave --head undocumented as alias for -m
+ " -m <count>, --max-count=<count>\n"
+ " Quit after printing <count> lines. This is meant to be\n"
+ " paired with --regex, but will work on its own.\n"
+ " --print Paired with --regex and --max-count to let content bypass\n"
" regex filter but still stop at number of matches.\n"
- " -t <count> print only the most recent <count> lines (implies -d)\n"
- " -t '<time>' print most recent lines since specified time (implies -d)\n"
- " -T <count> print only the most recent <count> lines (does not imply -d)\n"
- " -T '<time>' print most recent lines since specified time (not imply -d)\n"
+ // Leave --tail undocumented as alias for -t
+ " -t <count> Print only the most recent <count> lines (implies -d)\n"
+ " -t '<time>' Print most recent lines since specified time (implies -d)\n"
+ " -T <count> Print only the most recent <count> lines (does not imply -d)\n"
+ " -T '<time>' Print most recent lines since specified time (not imply -d)\n"
" count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'\n"
" 'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format\n"
- " -g get the size of the log's ring buffer and exit\n"
- " --buffer-size\n"
- " -G <size> set size of log ring buffer, may suffix with K or M.\n"
- " --buffer-size=<size>\n"
- " -L dump logs from prior to last reboot\n"
- " --last\n"
+ " -g, --buffer-size Get the size of the ring buffer.\n"
+ " -G <size>, --buffer-size=<size>\n"
+ " Set size of log ring buffer, may suffix with K or M.\n"
+ " -L, -last Dump logs from prior to last reboot\n"
// Leave security (Device Owner only installations) and
// kernel (userdebug and eng) buffers undocumented.
- " -b <buffer> Request alternate ring buffer, 'main', 'system', 'radio',\n"
- " --buffer=<buffer> 'events', 'crash', 'default' or 'all'. Multiple -b\n"
- " parameters are allowed and results are interleaved. The\n"
- " default is -b main -b system -b crash.\n"
- " -B output the log in binary.\n"
- " --binary\n"
- " -S output statistics.\n"
- " --statistics\n"
- " -p print prune white and ~black list. Service is specified as\n"
- " --prune UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
+ " -b <buffer>, --buffer=<buffer> Request alternate ring buffer, 'main',\n"
+ " 'system', 'radio', 'events', 'crash', 'default' or 'all'.\n"
+ " Multiple -b parameters or comma separated list of buffers are\n"
+ " allowed. Buffers interleaved. Default -b main,system,crash.\n"
+ " Permits property expansion.\n"
+ " -B, --binary Output the log in binary.\n"
+ " -S, --statistics Output statistics.\n"
+ " -p, --prune Print prune white and ~black list. Service is specified as\n"
+ " UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
" with ~, otherwise weighed for longevity if unadorned. All\n"
" other pruning activity is oldest first. Special case ~!\n"
" represents an automatic quicker pruning for the noisiest\n"
" UID as determined by the current statistics.\n"
- " -P '<list> ...' set prune white and ~black list, using same format as\n"
- " --prune='<list> ...' printed above. Must be quoted.\n"
+ " -P '<list> ...', --prune='<list> ...'\n"
+ " Set prune white and ~black list, using same format as\n"
+ " listed above. Must be quoted.\n"
" --pid=<pid> Only prints logs from the given pid.\n"
- // Check ANDROID_LOG_WRAP_DEFAULT_TIMEOUT value
+ // Check ANDROID_LOG_WRAP_DEFAULT_TIMEOUT value for match to 2 hours
" --wrap Sleep for 2 hours or when buffer about to wrap whichever\n"
" comes first. Improves efficiency of polling by providing\n"
" an about-to-wrap wakeup.\n");
- fprintf(stderr,"\nfilterspecs are a series of \n"
+ fprintf(stderr,"\nProperty expansion where available, may need to be single quoted to prevent\n"
+ "shell expansion:\n"
+ " ${key} - Expand string with property value associated with key\n"
+ " ${key:-default} - Expand, if property key value clear, use default\n"
+ "\nfilterspecs are a series of \n"
" <tag>[:priority]\n\n"
"where <tag> is a log component tag (or * for all) and priority is:\n"
" V Verbose (default for <tag>)\n"
@@ -394,7 +397,7 @@
}
/*String to unsigned int, returns -1 if it fails*/
-static bool getSizeTArg(char *ptr, size_t *val, size_t min = 0,
+static bool getSizeTArg(const char *ptr, size_t *val, size_t min = 0,
size_t max = SIZE_MAX)
{
if (!ptr) {
@@ -535,6 +538,49 @@
return retval;
}
+// Expand multiple flat property references ${<tag>:-default} or ${tag}.
+//
+// ToDo: Do we permit nesting?
+// ${persist.logcat.something:-${ro.logcat.something:-maybesomething}}
+// For now this will result in a syntax error for caller and is acceptable.
+//
+std::string expand(const char *str)
+{
+ std::string retval(str);
+
+ // Caller has no use for ${, } or :- as literals so no use for escape
+ // character. Result expectations are a number or a string, with validity
+ // checking for both in caller. Recursive expansion or other syntax errors
+ // will result in content caller can not obviously tolerate, error must
+ // report substring if applicable, expanded and original content (if
+ // different) so that it will be clear to user what they did wrong.
+ for (size_t pos; (pos = retval.find("${")) != std::string::npos; ) {
+ size_t epos = retval.find("}", pos + 2);
+ if (epos == std::string::npos) {
+ break; // Caller will error out, showing this unexpanded.
+ }
+ size_t def = retval.find(":-", pos + 2);
+ if (def >= epos) {
+ def = std::string::npos;
+ }
+ std::string default_value("");
+ std::string key;
+ if (def == std::string::npos) {
+ key = retval.substr(pos + 2, epos - (pos + 2));
+ } else {
+ key = retval.substr(pos + 2, def - (pos + 2));
+ default_value = retval.substr(def + 2, epos - (def + 2));
+ }
+ char value[PROPERTY_VALUE_MAX];
+ property_get(key.c_str(), value, default_value.c_str());
+ // Caller will error out, syntactically empty content at this point
+ // will not be tolerated as expected.
+ retval.replace(pos, epos - pos + 1, value);
+ }
+
+ return retval;
+}
+
} /* namespace android */
@@ -765,111 +811,75 @@
break;
case 'b': {
- if (strcmp(optarg, "default") == 0) {
- for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- switch (i) {
- case LOG_ID_SECURITY:
- case LOG_ID_EVENTS:
- continue;
- case LOG_ID_MAIN:
- case LOG_ID_SYSTEM:
- case LOG_ID_CRASH:
- break;
- default:
- continue;
- }
+ unsigned idMask = 0;
+ std::string expanded = expand(optarg);
+ std::istringstream copy(expanded);
+ std::string token;
+ // wish for strtok and ",:; \t\n\r\f" for hidden flexibility
+ while (std::getline(copy, token, ',')) { // settle for ","
+ if (token.compare("default") == 0) {
+ idMask |= (1 << LOG_ID_MAIN) |
+ (1 << LOG_ID_SYSTEM) |
+ (1 << LOG_ID_CRASH);
+ } else if (token.compare("all") == 0) {
+ idMask = (unsigned)-1;
+ } else {
+ log_id_t log_id = android_name_to_log_id(token.c_str());
+ const char *name = android_log_id_to_name(log_id);
- const char *name = android_log_id_to_name((log_id_t)i);
- log_id_t log_id = android_name_to_log_id(name);
-
- if (log_id != (log_id_t)i) {
- continue;
- }
-
- bool found = false;
- for (dev = devices; dev; dev = dev->next) {
- if (!strcmp(optarg, dev->device)) {
- found = true;
- break;
+ if (token.compare(name) != 0) {
+ bool strDifferent = expanded.compare(token);
+ if (expanded.compare(optarg)) {
+ expanded += " expanded from ";
+ expanded += optarg;
}
- if (!dev->next) {
- break;
+ if (strDifferent) {
+ expanded = token + " within " + expanded;
}
+ logcat_panic(true, "unknown buffer -b %s\n",
+ expanded.c_str());
}
- if (found) {
- break;
- }
-
- log_device_t* d = new log_device_t(name, false);
-
- if (dev) {
- dev->next = d;
- dev = d;
- } else {
- devices = dev = d;
- }
- g_devCount++;
+ idMask |= (1 << log_id);
}
- break;
}
- if (strcmp(optarg, "all") == 0) {
- for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- const char *name = android_log_id_to_name((log_id_t)i);
- log_id_t log_id = android_name_to_log_id(name);
+ for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+ const char *name = android_log_id_to_name((log_id_t)i);
+ log_id_t log_id = android_name_to_log_id(name);
- if (log_id != (log_id_t)i) {
- continue;
- }
+ if (log_id != (log_id_t)i) {
+ continue;
+ }
+ if ((idMask & (1 << i)) == 0) {
+ continue;
+ }
- bool found = false;
- for (dev = devices; dev; dev = dev->next) {
- if (!strcmp(optarg, dev->device)) {
- found = true;
- break;
- }
- if (!dev->next) {
- break;
- }
- }
- if (found) {
+ bool found = false;
+ for (dev = devices; dev; dev = dev->next) {
+ if (!strcmp(name, dev->device)) {
+ found = true;
break;
}
-
- bool binary = !strcmp(name, "events") ||
- !strcmp(name, "security");
- log_device_t* d = new log_device_t(name, binary);
-
- if (dev) {
- dev->next = d;
- dev = d;
- } else {
- devices = dev = d;
- }
- g_devCount++;
- }
- break;
- }
-
- bool binary = !(strcmp(optarg, "events") &&
- strcmp(optarg, "security"));
-
- if (devices) {
- dev = devices;
- while (dev->next) {
- if (!strcmp(optarg, dev->device)) {
- dev = NULL;
+ if (!dev->next) {
break;
}
- dev = dev->next;
}
+ if (found) {
+ continue;
+ }
+
+ bool binary = !strcmp(name, "events") ||
+ !strcmp(name, "security");
+ log_device_t* d = new log_device_t(name, binary);
+
if (dev) {
- dev->next = new log_device_t(optarg, binary);
+ dev->next = d;
+ dev = d;
+ } else {
+ devices = dev = d;
}
- } else {
- devices = new log_device_t(optarg, binary);
+ g_devCount++;
}
- g_devCount++;
}
break;
@@ -885,22 +895,36 @@
g_outputFileName = optarg;
break;
- case 'r':
- if (!getSizeTArg(optarg, &g_logRotateSizeKBytes, 1)) {
- logcat_panic(true, "Invalid parameter %s to -r\n", optarg);
+ case 'r': {
+ std::string expanded = expand(optarg);
+ if (!getSizeTArg(expanded.c_str(), &g_logRotateSizeKBytes, 1)) {
+ if (expanded.compare(optarg)) {
+ expanded += " expanded from ";
+ expanded += optarg;
+ }
+ logcat_panic(true, "Invalid parameter -r %s\n",
+ expanded.c_str());
}
+ }
break;
- case 'n':
- if (!getSizeTArg(optarg, &g_maxRotatedLogs, 1)) {
- logcat_panic(true, "Invalid parameter %s to -n\n", optarg);
+ case 'n': {
+ std::string expanded = expand(optarg);
+ if (!getSizeTArg(expanded.c_str(), &g_maxRotatedLogs, 1)) {
+ if (expanded.compare(optarg)) {
+ expanded += " expanded from ";
+ expanded += optarg;
+ }
+ logcat_panic(true, "Invalid parameter -n %s\n",
+ expanded.c_str());
}
+ }
break;
case 'v':
err = setLogFormat (optarg);
if (err < 0) {
- logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
+ logcat_panic(true, "Invalid parameter -v %s\n", optarg);
}
hasSetLogFormat |= err;
break;
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index a28664e..3bf8a0b 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -56,6 +56,6 @@
LOCAL_MODULE := $(test_module_prefix)unit-tests
LOCAL_MODULE_TAGS := $(test_tags)
LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libcutils
LOCAL_SRC_FILES := $(test_src_files)
include $(BUILD_NATIVE_TEST)
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index a606b6f..997e682 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -25,11 +25,14 @@
#include <memory>
+#include <cutils/properties.h>
#include <gtest/gtest.h>
#include <log/log.h>
#include <log/logger.h>
#include <log/log_read.h>
+#define BIG_BUFFER (5 * 1024)
+
// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
// non-syscall libs. Since we are only using this in the emergency of
// a signal to stuff a terminating code into the logs, we will spin rather
@@ -54,7 +57,7 @@
"logcat -b radio -b events -b system -b main -d 2>/dev/null",
"r")));
- char buffer[5120];
+ char buffer[BIG_BUFFER];
int ids = 0;
int count = 0;
@@ -102,7 +105,7 @@
"logcat -v long -v year -b all -t 3 2>/dev/null",
"r")));
- char buffer[5120];
+ char buffer[BIG_BUFFER];
int count = 0;
@@ -165,7 +168,7 @@
"logcat -v long -v America/Los_Angeles -b all -t 3 2>/dev/null",
"r")));
- char buffer[5120];
+ char buffer[BIG_BUFFER];
count = 0;
@@ -189,7 +192,7 @@
"logcat -v long -v America/Los_Angeles -v zone -b all -t 3 2>/dev/null",
"r")));
- char buffer[5120];
+ char buffer[BIG_BUFFER];
int count = 0;
@@ -209,7 +212,7 @@
int count;
do {
- char buffer[5120];
+ char buffer[BIG_BUFFER];
snprintf(buffer, sizeof(buffer),
"logcat -v long -b radio -b events -b system -b main -t %d 2>/dev/null",
@@ -252,7 +255,7 @@
ASSERT_TRUE(NULL != (fp = popen("logcat -v long -b all -t 10 2>&1", "r")));
- char buffer[5120];
+ char buffer[BIG_BUFFER];
char *last_timestamp = NULL;
char *first_timestamp = NULL;
int count = 0;
@@ -315,7 +318,7 @@
"logcat -v brief -b events -t 100 2>/dev/null",
"r")));
- char buffer[5120];
+ char buffer[BIG_BUFFER];
int count = 0;
@@ -339,15 +342,17 @@
ASSERT_EQ(1, count);
}
-TEST(logcat, get_size) {
+int get_groups(const char *cmd) {
FILE *fp;
// NB: crash log only available in user space
- ASSERT_TRUE(NULL != (fp = popen(
- "logcat -v brief -b radio -b events -b system -b main -g 2>/dev/null",
- "r")));
+ EXPECT_TRUE(NULL != (fp = popen(cmd, "r")));
- char buffer[5120];
+ if (fp == NULL) {
+ return 0;
+ }
+
+ char buffer[BIG_BUFFER];
int count = 0;
@@ -407,7 +412,31 @@
pclose(fp);
- ASSERT_EQ(4, count);
+ return count;
+}
+
+TEST(logcat, get_size) {
+ ASSERT_EQ(4, get_groups(
+ "logcat -v brief -b radio -b events -b system -b main -g 2>/dev/null"));
+}
+
+// duplicate test for get_size, but use comma-separated list of buffers
+TEST(logcat, multiple_buffer) {
+ ASSERT_EQ(4, get_groups(
+ "logcat -v brief -b radio,events,system,main -g 2>/dev/null"));
+}
+
+// duplicate test for get_size, but use test.logcat.buffer property
+TEST(logcat, property_expand) {
+ property_set("test.logcat.buffer", "radio,events");
+ EXPECT_EQ(4, get_groups(
+ "logcat -v brief -b 'system,${test.logcat.buffer:-bogo},main' -g 2>/dev/null"));
+ property_set("test.logcat.buffer", "");
+}
+
+TEST(logcat, bad_buffer) {
+ ASSERT_EQ(0, get_groups(
+ "logcat -v brief -b radio,events,bogo,system,main -g 2>/dev/null"));
}
static void caught_blocking(int /*signum*/)
@@ -436,7 +465,7 @@
" logcat -v brief -b events 2>&1",
"r")));
- char buffer[5120];
+ char buffer[BIG_BUFFER];
int count = 0;
@@ -505,7 +534,7 @@
" logcat -v brief -b events -T 5 2>&1",
"r")));
- char buffer[5120];
+ char buffer[BIG_BUFFER];
int count = 0;
@@ -568,7 +597,7 @@
FILE *fp;
EXPECT_TRUE(NULL != (fp = popen(command, "r")));
if (fp) {
- char buffer[5120];
+ char buffer[BIG_BUFFER];
int count = 0;
while (fgets(buffer, sizeof(buffer), fp)) {
@@ -611,7 +640,7 @@
FILE *fp;
EXPECT_TRUE(NULL != (fp = popen(command, "r")));
- char buffer[5120];
+ char buffer[BIG_BUFFER];
int log_file_count = 0;
while (fgets(buffer, sizeof(buffer), fp)) {
@@ -784,7 +813,7 @@
" logcat -v brief -b events 2>&1",
"r")));
- char buffer[5120];
+ char buffer[BIG_BUFFER];
int count = 0;
@@ -845,7 +874,7 @@
return false;
}
- char buffer[5120];
+ char buffer[BIG_BUFFER];
while (fgets(buffer, sizeof(buffer), fp)) {
char *hold = *list;
@@ -874,7 +903,7 @@
static bool set_white_black(const char *list) {
FILE *fp;
- char buffer[5120];
+ char buffer[BIG_BUFFER];
snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list ? list : "");
fp = popen(buffer, "r");
@@ -936,7 +965,7 @@
FILE *fp;
int count = 0;
- char buffer[5120];
+ char buffer[BIG_BUFFER];
snprintf(buffer, sizeof(buffer), "logcat --pid %d -d -e logcat_test_a+b", getpid());
@@ -969,7 +998,7 @@
FILE *fp;
int count = 0;
- char buffer[5120];
+ char buffer[BIG_BUFFER];
snprintf(buffer, sizeof(buffer), "logcat --pid %d -d --max-count 3", getpid());