1 /*
2 // Copyright (c) 2014 Intel Corporation 
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 #ifdef TARGET_HAS_MULTIPLE_DISPLAY
17 #include <HwcTrace.h>
18 #include <binder/IServiceManager.h>
19 #include <Hwcomposer.h>
20 #include <DisplayAnalyzer.h>
21 #include <ExternalDevice.h>
22 #endif
23 
24 #include <MultiDisplayObserver.h>
25 
26 namespace android {
27 namespace intel {
28 
29 #ifdef TARGET_HAS_MULTIPLE_DISPLAY
30 
31 ////// MultiDisplayCallback
32 
MultiDisplayCallback(MultiDisplayObserver * dispObserver)33 MultiDisplayCallback::MultiDisplayCallback(MultiDisplayObserver *dispObserver)
34     : mDispObserver(dispObserver),
35       mVideoState(MDS_VIDEO_STATE_UNKNOWN)
36 {
37 }
38 
~MultiDisplayCallback()39 MultiDisplayCallback::~MultiDisplayCallback()
40 {
41     CTRACE();
42     mDispObserver = NULL;
43 }
44 
blankSecondaryDisplay(bool blank)45 status_t MultiDisplayCallback::blankSecondaryDisplay(bool blank)
46 {
47     ITRACE("blank: %d", blank);
48     mDispObserver->blankSecondaryDisplay(blank);
49     return NO_ERROR;
50 }
51 
updateVideoState(int sessionId,MDS_VIDEO_STATE state)52 status_t MultiDisplayCallback::updateVideoState(int sessionId, MDS_VIDEO_STATE state)
53 {
54     mVideoState = state;
55     ITRACE("state: %d", state);
56     mDispObserver->updateVideoState(sessionId, state);
57     return NO_ERROR;
58 }
59 
setHdmiTiming(const MDSHdmiTiming & timing)60 status_t MultiDisplayCallback::setHdmiTiming(const MDSHdmiTiming& timing)
61 {
62     mDispObserver->setHdmiTiming(timing);
63     return NO_ERROR;
64 }
65 
updateInputState(bool state)66 status_t MultiDisplayCallback::updateInputState(bool state)
67 {
68     //ITRACE("input state: %d", state);
69     mDispObserver->updateInputState(state);
70     return NO_ERROR;
71 }
72 
setHdmiScalingType(MDS_SCALING_TYPE type)73 status_t MultiDisplayCallback::setHdmiScalingType(MDS_SCALING_TYPE type)
74 {
75     ITRACE("scaling type: %d", type);
76     // Merrifield doesn't implement this API
77     return INVALID_OPERATION;
78 }
79 
setHdmiOverscan(int hValue,int vValue)80 status_t MultiDisplayCallback::setHdmiOverscan(int hValue, int vValue)
81 {
82     ITRACE("oversacn compensation, h: %d v: %d", hValue, vValue);
83     // Merrifield doesn't implement this API
84     return INVALID_OPERATION;
85 }
86 
87 ////// MultiDisplayObserver
88 
MultiDisplayObserver()89 MultiDisplayObserver::MultiDisplayObserver()
90     : mMDSCbRegistrar(NULL),
91       mMDSInfoProvider(NULL),
92       mMDSConnObserver(NULL),
93       mMDSDecoderConfig(NULL),
94       mMDSCallback(NULL),
95       mLock(),
96       mCondition(),
97       mThreadLoopCount(0),
98       mDeviceConnected(false),
99       mExternalHdmiTiming(false),
100       mInitialized(false)
101 {
102     CTRACE();
103 }
104 
~MultiDisplayObserver()105 MultiDisplayObserver::~MultiDisplayObserver()
106 {
107     WARN_IF_NOT_DEINIT();
108 }
109 
isMDSRunning()110 bool MultiDisplayObserver::isMDSRunning()
111 {
112     // Check if Multi Display service is running
113     sp<IServiceManager> sm = defaultServiceManager();
114     if (sm == NULL) {
115         ETRACE("fail to get service manager!");
116         return false;
117     }
118 
119     sp<IBinder> service = sm->checkService(String16(INTEL_MDS_SERVICE_NAME));
120     if (service == NULL) {
121         VTRACE("fail to get MultiDisplay service!");
122         return false;
123     }
124 
125     return true;
126 }
127 
initMDSClient()128 bool MultiDisplayObserver::initMDSClient()
129 {
130     sp<IServiceManager> sm = defaultServiceManager();
131     if (sm == NULL) {
132         ETRACE("Fail to get service manager");
133         return false;
134     }
135     sp<IMDService> mds = interface_cast<IMDService>(
136             sm->getService(String16(INTEL_MDS_SERVICE_NAME)));
137     if (mds == NULL) {
138         ETRACE("Fail to get MDS service");
139         return false;
140     }
141     mMDSCbRegistrar = mds->getCallbackRegistrar();
142     if (mMDSCbRegistrar.get() == NULL) {
143         ETRACE("failed to create mds base Client");
144         return false;
145     }
146 
147     mMDSCallback = new MultiDisplayCallback(this);
148     if (mMDSCallback.get() == NULL) {
149         ETRACE("failed to create MultiDisplayCallback");
150         deinitMDSClient();
151         return false;
152     }
153     mMDSInfoProvider = mds->getInfoProvider();
154     if (mMDSInfoProvider.get() == NULL) {
155         ETRACE("failed to create mds video Client");
156         return false;
157     }
158 
159     mMDSConnObserver = mds->getConnectionObserver();
160     if (mMDSConnObserver.get() == NULL) {
161         ETRACE("failed to create mds video Client");
162         return false;
163     }
164     mMDSDecoderConfig = mds->getDecoderConfig();
165     if (mMDSDecoderConfig.get() == NULL) {
166         ETRACE("failed to create mds decoder Client");
167         return false;
168     }
169 
170     status_t ret = mMDSCbRegistrar->registerCallback(mMDSCallback);
171     if (ret != NO_ERROR) {
172         ETRACE("failed to register callback");
173         deinitMDSClient();
174         return false;
175     }
176 
177     Drm *drm = Hwcomposer::getInstance().getDrm();
178     mDeviceConnected = drm->isConnected(IDisplayDevice::DEVICE_EXTERNAL);
179     ITRACE("MDS client is initialized");
180     return true;
181 }
182 
deinitMDSClient()183 void MultiDisplayObserver::deinitMDSClient()
184 {
185     if (mMDSCallback.get() && mMDSCbRegistrar.get()) {
186         mMDSCbRegistrar->unregisterCallback(mMDSCallback);
187     }
188 
189     mDeviceConnected = false;
190     mMDSCbRegistrar = NULL;
191     mMDSInfoProvider = NULL;
192     mMDSCallback = NULL;
193     mMDSConnObserver = NULL;
194     mMDSDecoderConfig = NULL;
195 }
196 
initMDSClientAsync()197 bool MultiDisplayObserver::initMDSClientAsync()
198 {
199     if (mThread.get()) {
200         WTRACE("working thread has been already created.");
201         return true;
202     }
203 
204     mThread = new MDSClientInitThread(this);
205     if (mThread.get() == NULL) {
206         ETRACE("failed to create MDS client init thread");
207         return false;
208     }
209     mThreadLoopCount = 0;
210     // TODO: check return value
211     mThread->run("MDSClientInitThread", PRIORITY_URGENT_DISPLAY);
212     return true;
213 }
214 
initialize()215 bool MultiDisplayObserver::initialize()
216 {
217     bool ret = true;
218     Mutex::Autolock _l(mLock);
219 
220     if (mInitialized) {
221         WTRACE("display observer has been initialized");
222         return true;
223     }
224 
225     // initialize MDS client once. This should succeed if MDS service starts
226     // before surfaceflinger service is started.
227     // if surface flinger runs first, MDS client will be initialized asynchronously in
228     // a working thread
229     if (isMDSRunning()) {
230         if (!initMDSClient()) {
231             ETRACE("failed to initialize MDS client");
232             // FIXME: NOT a common case for system server crash.
233             // Start a working thread to initialize MDS client if exception happens
234             ret = initMDSClientAsync();
235         }
236     } else {
237         ret = initMDSClientAsync();
238     }
239 
240     mInitialized = true;
241     return ret;
242 }
243 
deinitialize()244 void MultiDisplayObserver::deinitialize()
245 {
246     sp<MDSClientInitThread> detachedThread;
247     do {
248         Mutex::Autolock _l(mLock);
249 
250         if (mThread.get()) {
251             mCondition.signal();
252             detachedThread = mThread;
253             mThread = NULL;
254         }
255         mThreadLoopCount = 0;
256         deinitMDSClient();
257         mInitialized = false;
258     } while (0);
259 
260     if (detachedThread.get()) {
261         detachedThread->requestExitAndWait();
262         detachedThread = NULL;
263     }
264 }
265 
threadLoop()266 bool MultiDisplayObserver::threadLoop()
267 {
268     Mutex::Autolock _l(mLock);
269 
270     // try to create MDS client in the working thread
271     // multiple delayed attempts are made until MDS service starts.
272 
273     // Return false if MDS service is running or loop limit is reached
274     // such that thread becomes inactive.
275     if (isMDSRunning()) {
276         if (!initMDSClient()) {
277             ETRACE("failed to initialize MDS client");
278         }
279         return false;
280     }
281 
282     if (mThreadLoopCount++ > THREAD_LOOP_BOUND) {
283         ETRACE("failed to initialize MDS client, loop limit reached");
284         return false;
285     }
286 
287     status_t err = mCondition.waitRelative(mLock, milliseconds(THREAD_LOOP_DELAY));
288     if (err != -ETIMEDOUT) {
289         ITRACE("thread is interrupted");
290         return false;
291     }
292 
293     return true; // keep trying
294 }
295 
296 
blankSecondaryDisplay(bool blank)297 status_t MultiDisplayObserver::blankSecondaryDisplay(bool blank)
298 {
299     // blank secondary display
300     Hwcomposer::getInstance().getDisplayAnalyzer()->postBlankEvent(blank);
301     return 0;
302 }
303 
updateVideoState(int sessionId,MDS_VIDEO_STATE state)304 status_t MultiDisplayObserver::updateVideoState(int sessionId, MDS_VIDEO_STATE state)
305 {
306     Hwcomposer::getInstance().getDisplayAnalyzer()->postVideoEvent(
307         sessionId, (int)state);
308     return 0;
309 }
310 
setHdmiTiming(const MDSHdmiTiming & timing)311 status_t MultiDisplayObserver::setHdmiTiming(const MDSHdmiTiming& timing)
312 {
313     drmModeModeInfo mode;
314     mode.hdisplay = timing.width;
315     mode.vdisplay = timing.height;
316     mode.vrefresh = timing.refresh;
317     mode.flags = timing.flags;
318     ITRACE("timing to set: %dx%d@%dHz", timing.width, timing.height, timing.refresh);
319     ExternalDevice *dev =
320         (ExternalDevice *)Hwcomposer::getInstance().getDisplayDevice(HWC_DISPLAY_EXTERNAL);
321     if (dev) {
322         dev->setDrmMode(mode);
323     }
324 
325     mExternalHdmiTiming = true;
326     return 0;
327 }
328 
updateInputState(bool active)329 status_t MultiDisplayObserver::updateInputState(bool active)
330 {
331     Hwcomposer::getInstance().getDisplayAnalyzer()->postInputEvent(active);
332     return 0;
333 }
334 
335 
336 /// Public interfaces
337 
notifyHotPlug(bool connected)338 status_t MultiDisplayObserver::notifyHotPlug( bool connected)
339 {
340     {
341         // lock scope
342         Mutex::Autolock _l(mLock);
343         if (mMDSConnObserver.get() == NULL) {
344             return NO_INIT;
345         }
346 
347         if (connected == mDeviceConnected) {
348             WTRACE("hotplug event ignored");
349             return NO_ERROR;
350         }
351 
352         // clear it after externel device is disconnected
353         if (!connected) mExternalHdmiTiming = false;
354 
355         mDeviceConnected = connected;
356     }
357     return mMDSConnObserver->updateHdmiConnectionStatus(connected);
358 }
359 
getVideoSourceInfo(int sessionID,VideoSourceInfo * info)360 status_t MultiDisplayObserver::getVideoSourceInfo(int sessionID, VideoSourceInfo* info)
361 {
362     Mutex::Autolock _l(mLock);
363     if (mMDSInfoProvider.get() == NULL) {
364         return NO_INIT;
365     }
366 
367     if (info == NULL) {
368         ETRACE("invalid parameter");
369         return UNKNOWN_ERROR;
370     }
371 
372     MDSVideoSourceInfo videoInfo;
373     memset(&videoInfo, 0, sizeof(MDSVideoSourceInfo));
374     status_t ret = mMDSInfoProvider->getVideoSourceInfo(sessionID, &videoInfo);
375     if (ret == NO_ERROR) {
376         info->width     = videoInfo.displayW;
377         info->height    = videoInfo.displayH;
378         info->frameRate = videoInfo.frameRate;
379         info->isProtected = videoInfo.isProtected;
380         VTRACE("Video Session[%d] source info: %dx%d@%d", sessionID,
381                 info->width, info->height, info->frameRate);
382     }
383     return ret;
384 }
385 
getVideoSessionNumber()386 int MultiDisplayObserver::getVideoSessionNumber()
387 {
388     Mutex::Autolock _l(mLock);
389     if (mMDSInfoProvider.get() == NULL) {
390         return 0;
391     }
392 
393     return mMDSInfoProvider->getVideoSessionNumber();
394 }
395 
isExternalDeviceTimingFixed() const396 bool MultiDisplayObserver::isExternalDeviceTimingFixed() const
397 {
398     Mutex::Autolock _l(mLock);
399     return mExternalHdmiTiming;
400 }
401 
notifyWidiConnectionStatus(bool connected)402 status_t MultiDisplayObserver::notifyWidiConnectionStatus( bool connected)
403 {
404     Mutex::Autolock _l(mLock);
405     if (mMDSConnObserver.get() == NULL) {
406         return NO_INIT;
407     }
408     return mMDSConnObserver->updateWidiConnectionStatus(connected);
409 }
410 
setDecoderOutputResolution(int sessionID,int32_t width,int32_t height,int32_t offX,int32_t offY,int32_t bufWidth,int32_t bufHeight)411 status_t MultiDisplayObserver::setDecoderOutputResolution(
412         int sessionID,
413         int32_t width, int32_t height,
414         int32_t offX, int32_t offY,
415         int32_t bufWidth, int32_t bufHeight)
416 {
417     Mutex::Autolock _l(mLock);
418     if (mMDSDecoderConfig.get() == NULL) {
419         return NO_INIT;
420     }
421     if (width <= 0 || height <= 0 ||
422             offX < 0 || offY < 0 ||
423             bufWidth <= 0 || bufHeight <= 0) {
424         ETRACE(" Invalid parameter: %dx%d, %dx%d, %dx%d", width, height, offX, offY, bufWidth, bufHeight);
425         return UNKNOWN_ERROR;
426     }
427 
428     status_t ret = mMDSDecoderConfig->setDecoderOutputResolution(sessionID, width, height, offX, offY, bufWidth, bufHeight);
429     if (ret == NO_ERROR) {
430         ITRACE("Video Session[%d] output resolution %dx%d ", sessionID, width, height);
431     }
432     return ret;
433 }
434 
435 
436 #endif //TARGET_HAS_MULTIPLE_DISPLAY
437 
438 } // namespace intel
439 } // namespace android
440