| /* | 
 |  * Copyright 2016 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. | 
 |  */ | 
 |  | 
 | #define ATRACE_TAG ATRACE_TAG_GRAPHICS | 
 |  | 
 | #include "GpuService.h" | 
 |  | 
 | #include <android-base/stringprintf.h> | 
 | #include <binder/IPCThreadState.h> | 
 | #include <binder/IResultReceiver.h> | 
 | #include <binder/Parcel.h> | 
 | #include <binder/PermissionCache.h> | 
 | #include <cutils/properties.h> | 
 | #include <gpumem/GpuMem.h> | 
 | #include <gpuwork/GpuWork.h> | 
 | #include <gpustats/GpuStats.h> | 
 | #include <private/android_filesystem_config.h> | 
 | #include <tracing/GpuMemTracer.h> | 
 | #include <utils/String8.h> | 
 | #include <utils/Trace.h> | 
 | #include <vkjson.h> | 
 |  | 
 | #include <thread> | 
 |  | 
 | namespace android { | 
 |  | 
 | using base::StringAppendF; | 
 |  | 
 | namespace { | 
 | status_t cmdHelp(int out); | 
 | status_t cmdVkjson(int out, int err); | 
 | void dumpGameDriverInfo(std::string* result); | 
 | } // namespace | 
 |  | 
 | const String16 sDump("android.permission.DUMP"); | 
 |  | 
 | const char* const GpuService::SERVICE_NAME = "gpu"; | 
 |  | 
 | GpuService::GpuService() | 
 |       : mGpuMem(std::make_shared<GpuMem>()), | 
 |         mGpuWork(std::make_shared<gpuwork::GpuWork>()), | 
 |         mGpuStats(std::make_unique<GpuStats>()), | 
 |         mGpuMemTracer(std::make_unique<GpuMemTracer>()) { | 
 |  | 
 |     std::thread gpuMemAsyncInitThread([this]() { | 
 |         mGpuMem->initialize(); | 
 |         mGpuMemTracer->initialize(mGpuMem); | 
 |     }); | 
 |     gpuMemAsyncInitThread.detach(); | 
 |  | 
 |     std::thread gpuWorkAsyncInitThread([this]() { | 
 |         mGpuWork->initialize(); | 
 |     }); | 
 |     gpuWorkAsyncInitThread.detach(); | 
 | }; | 
 |  | 
 | void GpuService::setGpuStats(const std::string& driverPackageName, | 
 |                              const std::string& driverVersionName, uint64_t driverVersionCode, | 
 |                              int64_t driverBuildTime, const std::string& appPackageName, | 
 |                              const int32_t vulkanVersion, GpuStatsInfo::Driver driver, | 
 |                              bool isDriverLoaded, int64_t driverLoadingTime) { | 
 |     mGpuStats->insertDriverStats(driverPackageName, driverVersionName, driverVersionCode, | 
 |                                  driverBuildTime, appPackageName, vulkanVersion, driver, | 
 |                                  isDriverLoaded, driverLoadingTime); | 
 | } | 
 |  | 
 | void GpuService::setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, | 
 |                                 const GpuStatsInfo::Stats stats, const uint64_t value) { | 
 |     mGpuStats->insertTargetStats(appPackageName, driverVersionCode, stats, value); | 
 | } | 
 |  | 
 | void GpuService::setUpdatableDriverPath(const std::string& driverPath) { | 
 |     IPCThreadState* ipc = IPCThreadState::self(); | 
 |     const int pid = ipc->getCallingPid(); | 
 |     const int uid = ipc->getCallingUid(); | 
 |  | 
 |     // only system_server is allowed to set updatable driver path | 
 |     if (uid != AID_SYSTEM) { | 
 |         ALOGE("Permission Denial: can't set updatable driver path from pid=%d, uid=%d\n", pid, uid); | 
 |         return; | 
 |     } | 
 |  | 
 |     std::lock_guard<std::mutex> lock(mLock); | 
 |     mDeveloperDriverPath = driverPath; | 
 | } | 
 |  | 
 | std::string GpuService::getUpdatableDriverPath() { | 
 |     std::lock_guard<std::mutex> lock(mLock); | 
 |     return mDeveloperDriverPath; | 
 | } | 
 |  | 
 | status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<String16>& args) { | 
 |     ATRACE_CALL(); | 
 |  | 
 |     ALOGV("shellCommand"); | 
 |     for (size_t i = 0, n = args.size(); i < n; i++) | 
 |         ALOGV("  arg[%zu]: '%s'", i, String8(args[i]).string()); | 
 |  | 
 |     if (args.size() >= 1) { | 
 |         if (args[0] == String16("vkjson")) return cmdVkjson(out, err); | 
 |         if (args[0] == String16("help")) return cmdHelp(out); | 
 |     } | 
 |     // no command, or unrecognized command | 
 |     cmdHelp(err); | 
 |     return BAD_VALUE; | 
 | } | 
 |  | 
 | status_t GpuService::doDump(int fd, const Vector<String16>& args, bool /*asProto*/) { | 
 |     std::string result; | 
 |  | 
 |     IPCThreadState* ipc = IPCThreadState::self(); | 
 |     const int pid = ipc->getCallingPid(); | 
 |     const int uid = ipc->getCallingUid(); | 
 |  | 
 |     if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) { | 
 |         StringAppendF(&result, "Permission Denial: can't dump gpu from pid=%d, uid=%d\n", pid, uid); | 
 |     } else { | 
 |         bool dumpAll = true; | 
 |         bool dumpDriverInfo = false; | 
 |         bool dumpMem = false; | 
 |         bool dumpStats = false; | 
 |         bool dumpWork = false; | 
 |         size_t numArgs = args.size(); | 
 |  | 
 |         if (numArgs) { | 
 |             for (size_t index = 0; index < numArgs; ++index) { | 
 |                 if (args[index] == String16("--gpustats")) { | 
 |                     dumpStats = true; | 
 |                 } else if (args[index] == String16("--gpudriverinfo")) { | 
 |                     dumpDriverInfo = true; | 
 |                 } else if (args[index] == String16("--gpumem")) { | 
 |                     dumpMem = true; | 
 |                 } else if (args[index] == String16("--gpuwork")) { | 
 |                     dumpWork = true; | 
 |                 } | 
 |             } | 
 |             dumpAll = !(dumpDriverInfo || dumpMem || dumpStats || dumpWork); | 
 |         } | 
 |  | 
 |         if (dumpAll || dumpDriverInfo) { | 
 |             dumpGameDriverInfo(&result); | 
 |             result.append("\n"); | 
 |         } | 
 |         if (dumpAll || dumpMem) { | 
 |             mGpuMem->dump(args, &result); | 
 |             result.append("\n"); | 
 |         } | 
 |         if (dumpAll || dumpStats) { | 
 |             mGpuStats->dump(args, &result); | 
 |             result.append("\n"); | 
 |         } | 
 |          if (dumpAll || dumpWork) { | 
 |             mGpuWork->dump(args, &result); | 
 |             result.append("\n"); | 
 |         } | 
 |     } | 
 |  | 
 |     write(fd, result.c_str(), result.size()); | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | status_t cmdHelp(int out) { | 
 |     FILE* outs = fdopen(out, "w"); | 
 |     if (!outs) { | 
 |         ALOGE("vkjson: failed to create out stream: %s (%d)", strerror(errno), errno); | 
 |         return BAD_VALUE; | 
 |     } | 
 |     fprintf(outs, | 
 |             "GPU Service commands:\n" | 
 |             "  vkjson   dump Vulkan properties as JSON\n"); | 
 |     fclose(outs); | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 | void vkjsonPrint(FILE* out) { | 
 |     std::string json = VkJsonInstanceToJson(VkJsonGetInstance()); | 
 |     fwrite(json.data(), 1, json.size(), out); | 
 |     fputc('\n', out); | 
 | } | 
 |  | 
 | status_t cmdVkjson(int out, int /*err*/) { | 
 |     FILE* outs = fdopen(out, "w"); | 
 |     if (!outs) { | 
 |         int errnum = errno; | 
 |         ALOGE("vkjson: failed to create output stream: %s", strerror(errnum)); | 
 |         return -errnum; | 
 |     } | 
 |     vkjsonPrint(outs); | 
 |     fclose(outs); | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 | void dumpGameDriverInfo(std::string* result) { | 
 |     if (!result) return; | 
 |  | 
 |     char stableGameDriver[PROPERTY_VALUE_MAX] = {}; | 
 |     property_get("ro.gfx.driver.0", stableGameDriver, "unsupported"); | 
 |     StringAppendF(result, "Stable Game Driver: %s\n", stableGameDriver); | 
 |  | 
 |     char preReleaseGameDriver[PROPERTY_VALUE_MAX] = {}; | 
 |     property_get("ro.gfx.driver.1", preReleaseGameDriver, "unsupported"); | 
 |     StringAppendF(result, "Pre-release Game Driver: %s\n", preReleaseGameDriver); | 
 | } | 
 |  | 
 | } // anonymous namespace | 
 |  | 
 | } // namespace android |