/* * Copyright (C) 2013 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 "rsUtils.h" #include "rsCppUtils.h" #include <string> #include <string.h> #ifndef RS_COMPATIBILITY_LIB #include <sys/wait.h> #endif namespace android { namespace renderscript { const char * rsuCopyString(const char *name) { return rsuCopyString(name, strlen(name)); } const char * rsuCopyString(const char *name, size_t len) { char *n = new char[len+1]; memcpy(n, name, len); n[len] = 0; return n; } const char* rsuJoinStrings(int n, const char* const* strs) { std::string tmp; for (int i = 0; i < n; i++) { if (i > 0) { tmp.append(" "); } tmp.append(strs[i]); } return strndup(tmp.c_str(), tmp.size()); } #ifndef RS_COMPATIBILITY_LIB bool rsuExecuteCommand(const char *exe, int nArgs, const char * const *args) { std::unique_ptr<const char> joined(rsuJoinStrings(nArgs, args)); ALOGV("Invoking %s with args '%s'", exe, joined.get()); pid_t pid = fork(); switch (pid) { case -1: { // Error occurred (we attempt no recovery) ALOGE("Fork of \"%s\" failed with error %s", exe, strerror(errno)); return false; } case 0: { // Child process // No (direct or indirect) call to malloc between fork and exec. It is // possible that a different thread holds the heap lock before the fork. // ProcessManager in libcore can reap unclaimed SIGCHLDs in its process // group. To ensure that the exit signal is not caught by // ProcessManager and instead sent to libRS, set the child's PGID to its // PID. setpgid(0, 0); execv(exe, (char * const *)args); ALOGE("execv() failed: %s", strerror(errno)); abort(); return false; } default: { // Parent process (actual driver) // Wait on child process to finish execution. int status = 0; pid_t w = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); if (w == -1) { ALOGE("Waitpid of \"%s\" failed with error %s", exe, strerror(errno)); return false; } if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { return true; } ALOGE("Child process \"%s\" terminated with status %d", exe, status); return false; } } } #endif // RS_COMPATIBILITY_LIB } }