You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
292 lines
8.8 KiB
292 lines
8.8 KiB
4 months ago
|
/*
|
||
|
* 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 <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <utils/KeyedVector.h>
|
||
|
#include <utils/String8.h>
|
||
|
#include <utils/Log.h>
|
||
|
#include <cutils/properties.h>
|
||
|
#include <binder/IPCThreadState.h>
|
||
|
#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<std::string> 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<std::string> 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<std::string> 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<INxMediaPlayerStore_V1_1> 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<int32_t> transCheckPermissiveForPlayer = playerStore->checkFileAccess(fdHandle);
|
||
|
(void)native_handle_delete(nativeHdl);
|
||
|
if (!transCheckPermissiveForPlayer.isOk() || static_cast<int32_t>(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;
|
||
|
}
|