1 /* 2 // Copyright(c)2014 IntelCorporation 3 // 4 // LicensedundertheApacheLicense,Version2.0(the"License"); 5 // youmaynotusethisfileexceptincompliancewiththeLicense. 6 // YoumayobtainacopyoftheLicenseat 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unlessrequiredbyapplicablelaworagreedtoinwriting,software 11 // distributedundertheLicenseisdistributedonan"ASIS"BASIS, 12 // WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. 13 // SeetheLicenseforthespecificlanguagegoverningpermissionsand 14 // limitationsundertheLicense. 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 33 MultiDisplayCallback::MultiDisplayCallback(MultiDisplayObserver *dispObserver) 34 : mDispObserver(dispObserver), 35 mVideoState(MDS_VIDEO_STATE_UNKNOWN) 36 { 37 } 38 39 MultiDisplayCallback::~MultiDisplayCallback() 40 { 41 CTRACE(); 42 mDispObserver = NULL; 43 } 44 45 status_t MultiDisplayCallback::blankSecondaryDisplay(bool blank) 46 { 47 ITRACE("blank: %d", blank); 48 mDispObserver->blankSecondaryDisplay(blank); 49 return NO_ERROR; 50 } 51 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 60 status_t MultiDisplayCallback::setHdmiTiming(const MDSHdmiTiming& timing) 61 { 62 mDispObserver->setHdmiTiming(timing); 63 return NO_ERROR; 64 } 65 66 status_t MultiDisplayCallback::updateInputState(bool state) 67 { 68 //ITRACE("input state: %d", state); 69 mDispObserver->updateInputState(state); 70 return NO_ERROR; 71 } 72 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 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 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 105 MultiDisplayObserver::~MultiDisplayObserver() 106 { 107 WARN_IF_NOT_DEINIT(); 108 } 109 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 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 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 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 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 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 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 297 status_t MultiDisplayObserver::blankSecondaryDisplay(bool blank) 298 { 299 // blank secondary display 300 Hwcomposer::getInstance().getDisplayAnalyzer()->postBlankEvent(blank); 301 return 0; 302 } 303 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 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 329 status_t MultiDisplayObserver::updateInputState(bool active) 330 { 331 Hwcomposer::getInstance().getDisplayAnalyzer()->postInputEvent(active); 332 return 0; 333 } 334 335 336 /// Public interfaces 337 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 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 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 396 bool MultiDisplayObserver::isExternalDeviceTimingFixed() const 397 { 398 Mutex::Autolock _l(mLock); 399 return mExternalHdmiTiming; 400 } 401 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 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