1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "TestPlayerStub"
19 #include "utils/Log.h"
20 
21 #include "TestPlayerStub.h"
22 
23 #include <dlfcn.h>  // for dlopen/dlclose
24 #include <stdlib.h>
25 #include <string.h>
26 #include <cutils/properties.h>
27 #include <utils/Errors.h>  // for status_t
28 
29 #include "media/MediaPlayerInterface.h"
30 
31 
32 namespace {
33 using android::status_t;
34 using android::MediaPlayerBase;
35 
36 const char *kTestUrlScheme = "test:";
37 const char *kUrlParam = "url=";
38 
39 const char *kBuildTypePropName = "ro.build.type";
40 const char *kEngBuild = "eng";
41 const char *kTestBuild = "test";
42 
43 // @return true if the current build is 'eng' or 'test'.
isTestBuild()44 bool isTestBuild()
45 {
46     char prop[PROPERTY_VALUE_MAX] = { '\0', };
47 
48     property_get(kBuildTypePropName, prop, "\0");
49     return strcmp(prop, kEngBuild) == 0 || strcmp(prop, kTestBuild) == 0;
50 }
51 
52 // @return true if the url scheme is 'test:'
isTestUrl(const char * url)53 bool isTestUrl(const char *url)
54 {
55     return url && strncmp(url, kTestUrlScheme, strlen(kTestUrlScheme)) == 0;
56 }
57 
58 }  // anonymous namespace
59 
60 namespace android {
61 
TestPlayerStub()62 TestPlayerStub::TestPlayerStub()
63     :mUrl(NULL), mFilename(NULL), mContentUrl(NULL),
64      mHandle(NULL), mNewPlayer(NULL), mDeletePlayer(NULL),
65      mPlayer(NULL) { }
66 
~TestPlayerStub()67 TestPlayerStub::~TestPlayerStub()
68 {
69     resetInternal();
70 }
71 
initCheck()72 status_t TestPlayerStub::initCheck()
73 {
74     return isTestBuild() ? OK : INVALID_OPERATION;
75 }
76 
77 // Parse mUrl to get:
78 // * The library to be dlopened.
79 // * The url to be passed to the real setDataSource impl.
80 //
81 // mUrl is expected to be in following format:
82 //
83 // test:<name of the .so>?url=<url for setDataSource>
84 //
85 // The value of the url parameter is treated as a string (no
86 // unescaping of illegal charaters).
parseUrl()87 status_t TestPlayerStub::parseUrl()
88 {
89     if (strlen(mUrl) < strlen(kTestUrlScheme)) {
90         resetInternal();
91         return BAD_VALUE;
92     }
93 
94     char *i = mUrl + strlen(kTestUrlScheme);
95 
96     mFilename = i;
97 
98     while (*i != '\0' && *i != '?') {
99         ++i;
100     }
101 
102     if (*i == '\0' || strncmp(i + 1, kUrlParam, strlen(kUrlParam)) != 0) {
103         resetInternal();
104         return BAD_VALUE;
105     }
106     *i = '\0';  // replace '?' to nul-terminate mFilename
107 
108     mContentUrl = i + 1 + strlen(kUrlParam);
109     return OK;
110 }
111 
112 // Load the dynamic library.
113 // Create the test player.
114 // Call setDataSource on the test player with the url in param.
setDataSource(const sp<IMediaHTTPService> & httpService,const char * url,const KeyedVector<String8,String8> * headers)115 status_t TestPlayerStub::setDataSource(
116         const sp<IMediaHTTPService> &httpService,
117         const char *url,
118         const KeyedVector<String8, String8> *headers) {
119     if (!isTestUrl(url) || NULL != mHandle) {
120         return INVALID_OPERATION;
121     }
122 
123     mUrl = strdup(url);
124 
125     status_t status = parseUrl();
126 
127     if (OK != status) {
128         resetInternal();
129         return status;
130     }
131 
132     ::dlerror();  // Clears any pending error.
133 
134     // Load the test player from the url. dlopen will fail if the lib
135     // is not there. dls are under /system/lib
136     // None of the entry points should be NULL.
137     mHandle = ::dlopen(mFilename, RTLD_NOW | RTLD_GLOBAL);
138     if (!mHandle) {
139         ALOGE("dlopen failed: %s", ::dlerror());
140         resetInternal();
141         return UNKNOWN_ERROR;
142     }
143 
144     // Load the 2 entry points to create and delete instances.
145     const char *err;
146     mNewPlayer = reinterpret_cast<NEW_PLAYER>(dlsym(mHandle,
147                                                     "newPlayer"));
148     err = ::dlerror();
149     if (err || mNewPlayer == NULL) {
150         // if err is NULL the string <null> is inserted in the logs =>
151         // mNewPlayer was NULL.
152         ALOGE("dlsym for newPlayer failed %s", err);
153         resetInternal();
154         return UNKNOWN_ERROR;
155     }
156 
157     mDeletePlayer = reinterpret_cast<DELETE_PLAYER>(dlsym(mHandle,
158                                                           "deletePlayer"));
159     err = ::dlerror();
160     if (err || mDeletePlayer == NULL) {
161         ALOGE("dlsym for deletePlayer failed %s", err);
162         resetInternal();
163         return UNKNOWN_ERROR;
164     }
165 
166     mPlayer = (*mNewPlayer)();
167     return mPlayer->setDataSource(httpService, mContentUrl, headers);
168 }
169 
170 // Internal cleanup.
resetInternal()171 status_t TestPlayerStub::resetInternal()
172 {
173     if(mUrl) {
174         free(mUrl);
175         mUrl = NULL;
176     }
177     mFilename = NULL;
178     mContentUrl = NULL;
179 
180     if (mPlayer) {
181         ALOG_ASSERT(mDeletePlayer != NULL, "mDeletePlayer is null");
182         (*mDeletePlayer)(mPlayer);
183         mPlayer = NULL;
184     }
185 
186     if (mHandle) {
187         ::dlclose(mHandle);
188         mHandle = NULL;
189     }
190     return OK;
191 }
192 
canBeUsed(const char * url)193 /* static */ bool TestPlayerStub::canBeUsed(const char *url)
194 {
195     return isTestBuild() && isTestUrl(url);
196 }
197 
198 }  // namespace android
199