/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2020. All rights reserved. * Description: NxMediaPlayerFactory class implement * Author: NxPlayer software group * Create: 2019-11-21 */ #define LOG_NDEBUG 0 #define LOG_TAG "NP_Factory" #include "NxMediaPlayerFactory.h" #include #include #include #include #include #include #include #include #include "NxMetadataRetriever.h" #include "NxMediaPlayerManage.h" using ::android::hardware::hidl_handle; namespace android { const std::string PROPERTY_NP_FF_NXPLAYER = "persist.sys.media.np.ff.nxplayer"; const std::string PROPERTY_NP_OUTPUT = "persist.sys.media.np.output"; const int BUF_SIZE = 1024; const int PROC_FILE_SIZE = 64; /* NxPlayer not support even in graphics output mode */ std::vector NxMediaPlayerFactory::g_accseeAllowedList = { "cent.qqmusic", "cts.media", "cts.mediastress", "cts.hardware", "media.cts", "areinfo.alibaba", "view.cts", "false.cts", "security.cts", "media.gts", "drm.cts", "d.process.media", "ernalstorageapp" }; /* NxPlayer in VO output mode */ std::vector NxMediaPlayerFactory::g_whiteListOthers = { "android.youtube", "android.chrome", "com.UCMobile", "cent.qqmusic", "cts.media", "cts.mediastress", "cts.hardware", "media.cts", "areinfo.alibaba", "view.cts", "false.cts", "security.cts", "media.gts", "drm.cts", "d.process.media", "ernalstorageapp", "ndroid.systemui", "s.device.statsd", /* com.android.server.cts.device.statsd.AtomTests */ "artext.true.cts", /* android.netsecpolicy.usescleartext.true.cts */ "unspecified.cts", /* android.netsecpolicy.usescleartext.unspecified.cts */ "mediastress.cts", /* android.mediastress.cts */ "id.cts.verifier", /* com.android.cts.verifier */ "roid.camera.cts", /* android.camera.cts */ }; /* MIDI case use default_player */ std::vector NxMediaPlayerFactory::g_fileExts = { ".mid", ".midi", ".smf", ".xmf", ".mxmf", ".imy", ".rtttl", ".rtx", ".ota" }; bool NxMediaPlayerFactory ::IsFileAccess(const int fd) const { ALOGD("call %s, fd=%d", __FUNCTION__, fd); sp playerStore; playerStore = INxMediaPlayerStore_V1_1::getService(); if (playerStore.get() == nullptr) { ALOGE("%s, get nxplayer service failed!", NMP_VIP_TAG); return false; } native_handle_t * const nativeHdl = native_handle_create(1, 0); if (nativeHdl == nullptr) { return false; } nativeHdl->data[0] = fd; hidl_handle fdHandle; fdHandle.setTo(nativeHdl, false); Return transCheckPermissiveForPlayer = playerStore->checkFileAccess(fdHandle); (void)native_handle_delete(nativeHdl); if (!transCheckPermissiveForPlayer.isOk() || static_cast(transCheckPermissiveForPlayer) == 0) { ALOGW("%s, nxplayer can not play it, access fd=%d permission denied", NMP_VIP_TAG, fd); return false; } return true; } float NxMediaPlayerFactory ::scoreFactory(const char *url, float curScore) { static const float kOurScore = 1.0; if (curScore >= kOurScore) { return 0.0; } /* unsupport play local stream with url, local stream uses fd to play */ if (url == nullptr || url[0] == '/') { ALOGW("%s, nxplayer can not play it, url is null or start with '/'", NMP_VIP_TAG); return 0.0; } if (!IsNxPlayerSupport()) { return 0.0; } /* unsupport url MidiFile use MidiFile for MIDI extensions */ unsigned int lenURL = strlen(url); for (auto it = g_fileExts.begin(); it != g_fileExts.end(); it++) { unsigned int len = strlen((*it).c_str()); int start = lenURL - len; if (start <= 0) { continue; } if (strncasecmp(url + start, (*it).c_str(), len) == 0) { ALOGW("%s, nxplayer can not play it, url extension name=%s", NMP_VIP_TAG, (*it).c_str()); return 0.0; } } ALOGD("call %s uri, kOurScore=%.1f", __FUNCTION__, kOurScore); return kOurScore; } float NxMediaPlayerFactory ::scoreFactory(int fd) { static const float kOurScore = 0.7; /* should <= 0.8 due to mid file */ char filePath[PROC_FILE_SIZE] = {0}; char dataSrcPath[BUF_SIZE + 1] = {0}; if (!IsNxPlayerSupport()) { return 0.0; } /* modify for cts testEncodingDetection */ int ret = snprintf_s(filePath, PROC_FILE_SIZE, PROC_FILE_SIZE - 1, "/proc/%d/fd/%d", getpid(), fd); if (ret < 0) { ALOGE("[%s:%d] snprintf_s failed!\n", __FUNCTION__, __LINE__); return 0.0; } readlink(filePath, dataSrcPath, BUF_SIZE); if (strstr(dataSrcPath, "android.media.cts") || strstr(dataSrcPath, "cts.verifier")) { ALOGW("%s, nxplayer can not play it, dataSrcPath restricted!", NMP_VIP_TAG); return 0.0; } if (!IsFileAccess(fd)) { return 0.0; } unsigned int lenURL = strlen(dataSrcPath); for (auto it = g_fileExts.begin(); it != g_fileExts.end(); it++) { unsigned int len = strlen((*it).c_str()); int start = lenURL - len; if (start <= 0) { continue; } if (strncasecmp(dataSrcPath + start, (*it).c_str(), len) == 0) { ALOGW("%s, nxplayer can not play it, file extension name=%s", NMP_VIP_TAG, (*it).c_str()); return 0.0; } } /* MIDI case end */ ALOGD("call %s fd, kOurScore=%.1f", __FUNCTION__, kOurScore); return kOurScore; } void NxMediaPlayerFactory ::GetProcessNameByPid(pid_t pid, const char *taskName) const { char procPidPath[BUF_SIZE] = {0}; char buf[BUF_SIZE] = {0}; if (taskName == nullptr) { ALOGE("invalid parameter, taskName is null"); return; } int ret = snprintf_s(procPidPath, BUF_SIZE, BUF_SIZE - 1, "/proc/%d/status", pid); if (ret < 0) { ALOGE("[%s:%d] snprintf_s failed!", __FUNCTION__, __LINE__); return; } FILE *fp = fopen(procPidPath, "r"); if (fp != nullptr) { if (fgets(buf, BUF_SIZE - 1, fp) == nullptr) { fclose(fp); return; } fclose(fp); ret = sscanf_s(buf, "%*s %s", taskName, BUF_SIZE - 1); if (ret < 0) { ALOGE("[%s:%d] sscanf_s failed!", __FUNCTION__, __LINE__); return; } } else { ALOGW("fopen(/proc/%d/status) to get application process name failed!", pid); } } bool NxMediaPlayerFactory ::IsNxPlayerDisable() const { char value[PROPERTY_VALUE_MAX] = {0}; int ret = property_get(PROPERTY_NP_FF_NXPLAYER.c_str(), value, "false"); bool disable = ((ret != 0) && (strcasecmp("false", value) == 0)); return disable; } bool NxMediaPlayerFactory ::IsOutPutOverLay() const { char value[PROPERTY_VALUE_MAX] = {0}; int ret = property_get(PROPERTY_NP_OUTPUT.c_str(), value, "NULL"); bool overLay = ((ret != 0) && (strcasecmp("overlay", value) == 0)); return overLay; } bool NxMediaPlayerFactory ::IsNxPlayerSupport() const { pid_t pid = IPCThreadState::self()->getCallingPid(); char strCallerName[BUF_SIZE] = {0}; /* NxPlayer not support when property [persist.sys.media.np.ff.nxplayer]=false */ bool disable = IsNxPlayerDisable(); if (disable) { ALOGW("%s, property [persist.sys.media.np.ff.nxplayer]=false, nxplayer is disabled", NMP_VIP_TAG); return false; } GetProcessNameByPid(pid, strCallerName); bool overlay = IsOutPutOverLay(); if (overlay) { auto index = std::find(g_accseeAllowedList.cbegin(), g_accseeAllowedList.cend(), strCallerName); if (index != g_accseeAllowedList.end()) { ALOGW("%s, caller name %s, nxplayer not support it in graphics output mode", NMP_VIP_TAG, strCallerName); return false; } ALOGI("%s, process %s call nxplayer in graphics output mode", NMP_VIP_TAG, strCallerName); return true; } auto index = std::find(g_whiteListOthers.cbegin(), g_whiteListOthers.cend(), strCallerName); if (index != g_whiteListOthers.end()) { ALOGW("%s, caller name %s, nxplayer not support it in VO output mode", NMP_VIP_TAG, strCallerName); return false; } ALOGI("%s, process %s call nxplayer in VO output mode", NMP_VIP_TAG, strCallerName); return true; } }; extern "C" android::NxMediaPlayerFactoryInterface *CreateNxMediaPlayerFactoryInterfaceInstance() { ALOGI("create NxMediaPlayerFactory"); return new ::android::NxMediaPlayerFactory(); } extern "C" void DestroyNxMediaPlayerFactoryInterfaceInstance(android::NxMediaPlayerFactoryInterface *factory) { ALOGI("destroy NxMediaPlayerFactory"); delete factory; }