1 /* 2 * Copyright (C) 2022 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 package com.android.car.oem; 18 19 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 20 21 import android.annotation.Nullable; 22 import android.car.builtin.content.pm.PackageManagerHelper; 23 import android.car.builtin.os.BuildHelper; 24 import android.car.builtin.os.TraceHelper; 25 import android.car.builtin.util.Slogf; 26 import android.car.builtin.util.TimingsTraceLog; 27 import android.car.oem.IOemCarAudioDuckingService; 28 import android.car.oem.IOemCarAudioFocusService; 29 import android.car.oem.IOemCarAudioVolumeService; 30 import android.car.oem.IOemCarService; 31 import android.car.oem.IOemCarServiceCallback; 32 import android.content.ComponentName; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.content.ServiceConnection; 36 import android.content.pm.PackageInfo; 37 import android.content.pm.PackageManager.NameNotFoundException; 38 import android.content.res.Resources; 39 import android.os.Binder; 40 import android.os.Handler; 41 import android.os.HandlerThread; 42 import android.os.IBinder; 43 import android.os.RemoteException; 44 import android.os.SystemClock; 45 import android.os.SystemProperties; 46 import android.os.UserHandle; 47 import android.text.TextUtils; 48 import android.util.Log; 49 import android.util.proto.ProtoOutputStream; 50 51 import com.android.car.CarServiceBase; 52 import com.android.car.CarServiceUtils; 53 import com.android.car.R; 54 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 55 import com.android.car.internal.util.IndentingPrintWriter; 56 import com.android.internal.annotations.GuardedBy; 57 import com.android.internal.annotations.VisibleForTesting; 58 59 import java.util.ArrayList; 60 import java.util.concurrent.CountDownLatch; 61 import java.util.concurrent.TimeUnit; 62 import java.util.concurrent.TimeoutException; 63 64 /** 65 * Manages access to OemCarService. 66 * 67 * <p>All calls in this class are blocking on OEM service initialization, so should be called as 68 * late as possible. 69 * 70 * <b>NOTE</b>: All {@link CarOemProxyService} call should be after init of ICarImpl. If any 71 * component calls {@link CarOemProxyService} before init of ICarImpl complete, it would throw 72 * {@link IllegalStateException}. 73 */ 74 public final class CarOemProxyService implements CarServiceBase { 75 76 private static final String TAG = CarOemProxyService.class.getSimpleName(); 77 private static final String CALL_TAG = CarOemProxyService.class.getSimpleName(); 78 private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG); 79 // mock component name for testing if system property is set. 80 private static final String PROPERTY_EMULATED_OEM_CAR_SERVICE = 81 "persist.com.android.car.internal.debug.oem_car_service"; 82 83 private final int mOemServiceConnectionTimeoutMs; 84 private final int mOemServiceReadyTimeoutMs; 85 private final Object mLock = new Object(); 86 private final boolean mIsFeatureEnabled; 87 private final Context mContext; 88 private final boolean mIsOemServiceBound; 89 private final CarOemProxyServiceHelper mHelper; 90 private final HandlerThread mHandlerThread; 91 private final Handler mHandler; 92 @GuardedBy("mLock") 93 private final ArrayList<CarOemProxyServiceCallback> mCallbacks = new ArrayList<>(); 94 95 96 private String mComponentName; 97 98 // True once OemService return true for {@code isOemServiceReady} call. It means that OEM 99 // service has completed all the initialization and ready to serve requests. 100 @GuardedBy("mLock") 101 private boolean mIsOemServiceReady; 102 // True once OEM service is connected. It means that OEM service has return binder for 103 // communication. OEM service may still not be ready. 104 @GuardedBy("mLock") 105 private boolean mIsOemServiceConnected; 106 107 @GuardedBy("mLock") 108 private boolean mInitComplete; 109 @GuardedBy("mLock") 110 private IOemCarService mOemCarService; 111 @GuardedBy("mLock") 112 private CarOemAudioFocusProxyService mCarOemAudioFocusProxyService; 113 @GuardedBy("mLock") 114 private CarOemAudioVolumeProxyService mCarOemAudioVolumeProxyService; 115 @GuardedBy("mLock") 116 private CarOemAudioDuckingProxyService mCarOemAudioDuckingProxyService; 117 private long mWaitForOemServiceConnectedDuration; 118 private long mWaitForOemServiceReadyDuration; 119 120 121 private final ServiceConnection mCarOemServiceConnection = new ServiceConnection() { 122 123 @Override 124 public void onServiceConnected(ComponentName componentName, IBinder iBinder) { 125 Slogf.i(TAG, "onServiceConnected: %s, %s", componentName, iBinder); 126 synchronized (mLock) { 127 if (mOemCarService == IOemCarService.Stub.asInterface(iBinder)) { 128 return; // already connected. 129 } 130 Slogf.i(TAG, "car oem service binder changed, was %s now: %s", 131 mOemCarService, iBinder); 132 mOemCarService = IOemCarService.Stub.asInterface(iBinder); 133 Slogf.i(TAG, "**CarOemService connected**"); 134 mIsOemServiceConnected = true; 135 mLock.notifyAll(); 136 } 137 } 138 139 @Override 140 public void onServiceDisconnected(ComponentName componentName) { 141 Slogf.e(TAG, "OEM service crashed. Crashing the CarService. ComponentName:%s", 142 componentName); 143 mHelper.crashCarService("Service Disconnected"); 144 } 145 }; 146 147 private final CountDownLatch mOemServiceReadyLatch = new CountDownLatch(1); 148 149 private final IOemCarServiceCallback mOemCarServiceCallback = new IOemCarServiceCallbackImpl(); 150 151 @VisibleForTesting CarOemProxyService(Context context)152 public CarOemProxyService(Context context) { 153 this(context, null); 154 } 155 156 @VisibleForTesting CarOemProxyService(Context context, CarOemProxyServiceHelper helper)157 public CarOemProxyService(Context context, CarOemProxyServiceHelper helper) { 158 this(context, helper, null); 159 } 160 CarOemProxyService(Context context, CarOemProxyServiceHelper helper, Handler handler)161 public CarOemProxyService(Context context, CarOemProxyServiceHelper helper, Handler handler) { 162 // Bind to the OemCarService 163 mContext = context; 164 Resources res = mContext.getResources(); 165 mOemServiceConnectionTimeoutMs = res 166 .getInteger(R.integer.config_oemCarService_connection_timeout_ms); 167 mOemServiceReadyTimeoutMs = res 168 .getInteger(R.integer.config_oemCarService_serviceReady_timeout_ms); 169 170 String componentName = res.getString(R.string.config_oemCarService); 171 172 if (TextUtils.isEmpty(componentName)) { 173 // mock component name for testing if system property is set. 174 String emulatedOemCarService = SystemProperties.get(PROPERTY_EMULATED_OEM_CAR_SERVICE, 175 ""); 176 if (!BuildHelper.isUserBuild() && emulatedOemCarService != null 177 && !emulatedOemCarService.isEmpty()) { 178 componentName = emulatedOemCarService; 179 Slogf.i(TAG, "Using emulated componentname for testing. ComponentName: %s", 180 mComponentName); 181 } 182 } 183 184 mComponentName = componentName; 185 186 Slogf.i(TAG, "Oem Car Service Config. Connection timeout:%s, Service Ready timeout:%d, " 187 + "component Name:%s", mOemServiceConnectionTimeoutMs, mOemServiceReadyTimeoutMs, 188 mComponentName); 189 190 if (isInvalidComponentName(context, mComponentName)) { 191 // feature disabled 192 mIsFeatureEnabled = false; 193 mIsOemServiceBound = false; 194 mHelper = null; 195 mHandlerThread = null; 196 mHandler = null; 197 Slogf.i(TAG, "**CarOemService is disabled.**"); 198 return; 199 } 200 201 Intent intent = (new Intent()) 202 .setComponent(ComponentName.unflattenFromString(mComponentName)); 203 204 Slogf.i(TAG, "Binding to Oem Service with intent: %s", intent); 205 mHandlerThread = CarServiceUtils.getHandlerThread("car_oem_service"); 206 mHandler = handler == null ? new Handler(mHandlerThread.getLooper()) : handler; 207 208 mIsOemServiceBound = mContext.bindServiceAsUser(intent, mCarOemServiceConnection, 209 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM); 210 211 if (mIsOemServiceBound) { 212 mIsFeatureEnabled = true; 213 Slogf.i(TAG, "OemCarService bounded."); 214 } else { 215 mIsFeatureEnabled = false; 216 Slogf.e(TAG, 217 "Couldn't bound to OemCarService. Oem service feature is marked disabled."); 218 } 219 mHelper = helper == null ? new CarOemProxyServiceHelper(mContext) : helper; 220 } 221 isInvalidComponentName(Context context, String componentName)222 private boolean isInvalidComponentName(Context context, String componentName) { 223 if (componentName == null || componentName.isEmpty()) { 224 if (DBG) { 225 Slogf.d(TAG, "ComponentName is null or empty."); 226 } 227 return true; 228 } 229 230 // Only pre-installed package can be used for OEM Service. 231 String packageName = ComponentName.unflattenFromString(componentName).getPackageName(); 232 PackageInfo info; 233 try { 234 info = context.getPackageManager().getPackageInfo(packageName, /* flags= */ 0); 235 } catch (NameNotFoundException e) { 236 Slogf.e(TAG, "componentName %s not found.", componentName); 237 return true; 238 } 239 240 if (info == null || info.applicationInfo == null 241 || !(PackageManagerHelper.isSystemApp(info.applicationInfo) 242 || PackageManagerHelper.isUpdatedSystemApp(info.applicationInfo) 243 || PackageManagerHelper.isOemApp(info.applicationInfo) 244 || PackageManagerHelper.isOdmApp(info.applicationInfo) 245 || PackageManagerHelper.isVendorApp(info.applicationInfo) 246 || PackageManagerHelper.isProductApp(info.applicationInfo) 247 || PackageManagerHelper.isSystemExtApp(info.applicationInfo))) { 248 if (DBG) { 249 Slogf.d(TAG, "Invalid component name. Info: %s", info); 250 } 251 return true; 252 } 253 254 if (DBG) { 255 Slogf.d(TAG, "Valid component name %s, ", componentName); 256 } 257 258 return false; 259 } 260 261 /** 262 * Registers callback to be called once OEM service is ready. 263 * 264 * <p>Other CarService components cannot call OEM service. But they can register a callback 265 * which would be called as soon as OEM Service is ready./ 266 */ registerCallback(CarOemProxyServiceCallback callback)267 public void registerCallback(CarOemProxyServiceCallback callback) { 268 synchronized (mLock) { 269 mCallbacks.add(callback); 270 } 271 } 272 273 /** 274 * Informs if OEM service is enabled. 275 */ isOemServiceEnabled()276 public boolean isOemServiceEnabled() { 277 synchronized (mLock) { 278 return mIsFeatureEnabled; 279 } 280 } 281 282 /** 283 * Informs if OEM service is ready. 284 */ isOemServiceReady()285 public boolean isOemServiceReady() { 286 synchronized (mLock) { 287 return mIsOemServiceReady; 288 } 289 } 290 291 @Override init()292 public void init() { 293 // Nothing to be done as OemCarService was initialized in the constructor. 294 } 295 296 @Override release()297 public void release() { 298 // Stop OEM Service; 299 if (mIsOemServiceBound) { 300 Slogf.i(TAG, "Unbinding Oem Service"); 301 mContext.unbindService(mCarOemServiceConnection); 302 } 303 } 304 305 @Override dump(IndentingPrintWriter writer)306 public void dump(IndentingPrintWriter writer) { 307 writer.println("***CarOemProxyService dump***"); 308 writer.increaseIndent(); 309 synchronized (mLock) { 310 writer.printf("mIsFeatureEnabled: %s\n", mIsFeatureEnabled); 311 writer.printf("mIsOemServiceBound: %s\n", mIsOemServiceBound); 312 writer.printf("mIsOemServiceReady: %s\n", mIsOemServiceReady); 313 writer.printf("mIsOemServiceConnected: %s\n", mIsOemServiceConnected); 314 writer.printf("mInitComplete: %s\n", mInitComplete); 315 writer.printf("OEM_CAR_SERVICE_CONNECTED_TIMEOUT_MS: %s\n", 316 mOemServiceConnectionTimeoutMs); 317 writer.printf("OEM_CAR_SERVICE_READY_TIMEOUT_MS: %s\n", mOemServiceReadyTimeoutMs); 318 writer.printf("mComponentName: %s\n", mComponentName); 319 writer.printf("waitForOemServiceConnected completed in : %d ms\n", 320 mWaitForOemServiceConnectedDuration); 321 writer.printf("waitForOemServiceReady completed in : %d ms\n", 322 mWaitForOemServiceReadyDuration); 323 // Dump other service components. 324 getCarOemAudioFocusService().dump(writer); 325 getCarOemAudioVolumeService().dump(writer); 326 // Dump OEM service stack 327 if (mIsOemServiceReady) { 328 writer.printf("OEM callstack\n"); 329 int timeoutMs = 2000; 330 try { 331 IOemCarService oemCarService = getOemService(); 332 writer.printf(mHelper.doBinderTimedCallWithTimeout(CALL_TAG, 333 () -> oemCarService.getAllStackTraces(), timeoutMs)); 334 } catch (TimeoutException e) { 335 writer.printf("Didn't received OEM stack within %d milliseconds.\n", timeoutMs); 336 } 337 } 338 // Dump helper 339 if (mHelper != null) { 340 mHelper.dump(writer); 341 } 342 } 343 writer.decreaseIndent(); 344 } 345 346 @Override 347 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dumpProto(ProtoOutputStream proto)348 public void dumpProto(ProtoOutputStream proto) {} 349 getOemServiceName()350 public String getOemServiceName() { 351 return mComponentName; 352 } 353 354 /** 355 * Gets OEM audio focus service. 356 */ 357 @Nullable getCarOemAudioFocusService()358 public CarOemAudioFocusProxyService getCarOemAudioFocusService() { 359 if (!mIsFeatureEnabled) { 360 if (DBG) { 361 Slogf.d(TAG, "Oem Car Service is disabled, returning null for" 362 + " getCarOemAudioFocusService"); 363 } 364 return null; 365 } 366 367 synchronized (mLock) { 368 if (mCarOemAudioFocusProxyService != null) { 369 return mCarOemAudioFocusProxyService; 370 } 371 } 372 373 waitForOemService(); 374 375 // Defaults to returning null service and try again next time the service is requested. 376 IOemCarService oemCarService = getOemService(); 377 IOemCarAudioFocusService oemAudioFocusService = mHelper.doBinderTimedCallWithDefaultValue( 378 CALL_TAG, () -> oemCarService.getOemAudioFocusService(), 379 /* defaultValue= */ null); 380 381 if (oemAudioFocusService == null) { 382 if (DBG) { 383 Slogf.d(TAG, "Oem Car Service doesn't implement AudioFocusService, returning null" 384 + " for getCarOemAudioFocusService"); 385 } 386 return null; 387 } 388 389 CarOemAudioFocusProxyService carOemAudioFocusProxyService = 390 new CarOemAudioFocusProxyService(mHelper, oemAudioFocusService); 391 synchronized (mLock) { 392 if (mCarOemAudioFocusProxyService != null) { 393 return mCarOemAudioFocusProxyService; 394 } 395 mCarOemAudioFocusProxyService = carOemAudioFocusProxyService; 396 Slogf.i(TAG, "CarOemAudioFocusProxyService is ready."); 397 return mCarOemAudioFocusProxyService; 398 } 399 } 400 401 /** 402 * Gets OEM audio volume service. 403 */ 404 @Nullable getCarOemAudioVolumeService()405 public CarOemAudioVolumeProxyService getCarOemAudioVolumeService() { 406 if (!mIsFeatureEnabled) { 407 if (DBG) { 408 Slogf.d(TAG, "Oem Car Service is disabled, returning null for" 409 + " getCarOemAudioVolumeService"); 410 } 411 return null; 412 } 413 414 synchronized (mLock) { 415 if (mCarOemAudioVolumeProxyService != null) { 416 return mCarOemAudioVolumeProxyService; 417 } 418 } 419 420 waitForOemService(); 421 IOemCarService oemCarService = getOemService(); 422 IOemCarAudioVolumeService oemAudioVolumeService = mHelper.doBinderTimedCallWithDefaultValue( 423 CALL_TAG, () -> oemCarService.getOemAudioVolumeService(), 424 /* defaultValue= */ null); 425 426 if (oemAudioVolumeService == null) { 427 if (DBG) { 428 Slogf.d(TAG, "Oem Car Service doesn't implement AudioVolumeService," 429 + "returning null for getCarOemAudioDuckingService"); 430 } 431 return null; 432 } 433 434 CarOemAudioVolumeProxyService carOemAudioVolumeProxyService = 435 new CarOemAudioVolumeProxyService(mHelper, oemAudioVolumeService); 436 synchronized (mLock) { 437 if (mCarOemAudioVolumeProxyService != null) { 438 return mCarOemAudioVolumeProxyService; 439 } 440 mCarOemAudioVolumeProxyService = carOemAudioVolumeProxyService; 441 Slogf.i(TAG, "CarOemAudioVolumeProxyService is ready."); 442 } 443 return carOemAudioVolumeProxyService; 444 } 445 446 /** 447 * Gets OEM audio ducking service. 448 */ 449 @Nullable getCarOemAudioDuckingService()450 public CarOemAudioDuckingProxyService getCarOemAudioDuckingService() { 451 if (!mIsFeatureEnabled) { 452 if (DBG) { 453 Slogf.d(TAG, "Oem Car Service is disabled, returning null for" 454 + " getCarOemAudioDuckingService"); 455 } 456 return null; 457 } 458 459 synchronized (mLock) { 460 if (mCarOemAudioDuckingProxyService != null) { 461 return mCarOemAudioDuckingProxyService; 462 } 463 } 464 465 waitForOemService(); 466 467 IOemCarService oemCarService = getOemService(); 468 IOemCarAudioDuckingService oemAudioDuckingService = 469 mHelper.doBinderTimedCallWithDefaultValue( 470 CALL_TAG, () -> oemCarService.getOemAudioDuckingService(), 471 /* defaultValue= */ null); 472 473 if (oemAudioDuckingService == null) { 474 if (DBG) { 475 Slogf.d(TAG, "Oem Car Service doesn't implement AudioDuckingService," 476 + "returning null for getCarOemAudioDuckingService"); 477 } 478 return null; 479 } 480 481 CarOemAudioDuckingProxyService carOemAudioDuckingProxyService = 482 new CarOemAudioDuckingProxyService(mHelper, oemAudioDuckingService); 483 synchronized (mLock) { 484 if (mCarOemAudioDuckingProxyService != null) { 485 return mCarOemAudioDuckingProxyService; 486 } 487 mCarOemAudioDuckingProxyService = carOemAudioDuckingProxyService; 488 Slogf.i(TAG, "CarOemAudioDuckingProxyService is ready."); 489 } 490 return carOemAudioDuckingProxyService; 491 } 492 493 /** 494 * Should be called when CarService is ready for communication. It updates the OEM service that 495 * CarService is ready. 496 */ onCarServiceReady()497 public void onCarServiceReady() { 498 TimingsTraceLog t = new TimingsTraceLog(TAG, TraceHelper.TRACE_TAG_CAR_SERVICE); 499 long startTime = SystemClock.uptimeMillis(); 500 t.traceBegin("waitForOemServiceConnected"); 501 waitForOemServiceConnected(); 502 mWaitForOemServiceConnectedDuration = SystemClock.uptimeMillis() - startTime; 503 t.traceEnd(); 504 505 IOemCarService oemCarService = getOemService(); 506 mHelper.doBinderOneWayCall(CALL_TAG, () -> { 507 try { 508 oemCarService.onCarServiceReady(mOemCarServiceCallback); 509 } catch (RemoteException ex) { 510 Slogf.e(TAG, "Binder call received RemoteException, calling to crash CarService", 511 ex); 512 } 513 }); 514 515 t.traceBegin("waitForOemServiceReady"); 516 startTime = SystemClock.uptimeMillis(); 517 waitForOemServiceReady(); 518 mWaitForOemServiceReadyDuration = SystemClock.uptimeMillis() - startTime; 519 t.traceEnd(); 520 } 521 waitForOemServiceConnected()522 private void waitForOemServiceConnected() { 523 synchronized (mLock) { 524 if (!mInitComplete) { 525 // No CarOemService call should be made before or during init of ICarImpl. 526 throw new IllegalStateException( 527 "CarOemService should not be call before CarService initialization"); 528 } 529 530 if (mIsOemServiceConnected) { 531 return; 532 } 533 waitForOemServiceConnectedLocked(); 534 } 535 } 536 537 @GuardedBy("mLock") waitForOemServiceConnectedLocked()538 private void waitForOemServiceConnectedLocked() { 539 long startTime = SystemClock.elapsedRealtime(); 540 long remainingTime = mOemServiceConnectionTimeoutMs; 541 542 while (!mIsOemServiceConnected && remainingTime > 0) { 543 try { 544 Slogf.i(TAG, "waiting to connect to OemService. wait time: %s", remainingTime); 545 mLock.wait(mOemServiceConnectionTimeoutMs); 546 remainingTime = mOemServiceConnectionTimeoutMs 547 - (SystemClock.elapsedRealtime() - startTime); 548 } catch (InterruptedException e) { 549 Thread.currentThread().interrupt(); 550 Slogf.w(TAG, "InterruptedException received. Reset interrupted status.", e); 551 } 552 } 553 554 if (!mIsOemServiceConnected) { 555 Slogf.e(TAG, "OEM Service is not connected within: %dms, calling to crash CarService", 556 mOemServiceConnectionTimeoutMs); 557 mHelper.crashCarService("OEM Service not connected"); 558 } 559 } 560 waitForOemService()561 private void waitForOemService() { 562 waitForOemServiceConnected(); 563 waitForOemServiceReady(); 564 } 565 waitForOemServiceReady()566 private void waitForOemServiceReady() { 567 synchronized (mLock) { 568 if (mIsOemServiceReady) { 569 return; 570 } 571 } 572 573 try { 574 mOemServiceReadyLatch.await(mOemServiceReadyTimeoutMs, TimeUnit.MILLISECONDS); 575 } catch (InterruptedException e) { 576 Thread.currentThread().interrupt(); 577 Slogf.i(TAG, "Exception while waiting for OEM Service to be ready.", e); 578 } 579 580 synchronized (mLock) { 581 if (!mIsOemServiceReady) { 582 Slogf.e(TAG, "OEM Service is not ready within: " + mOemServiceReadyTimeoutMs 583 + "ms, calling to crash CarService"); 584 mHelper.crashCarService("OEM Service not ready"); 585 } 586 } 587 Slogf.i(TAG, "OEM Service is ready."); 588 } 589 590 // Initialize all OEM related components. initOemServiceComponents()591 private void initOemServiceComponents() { 592 // Initialize all Oem Service components 593 getCarOemAudioFocusService(); 594 595 // Callback registered Car Service components for OEM service. 596 callCarServiceComponents(); 597 } 598 callCarServiceComponents()599 private void callCarServiceComponents() { 600 synchronized (mLock) { 601 for (int i = 0; i < mCallbacks.size(); i++) { 602 mCallbacks.get(i).onOemServiceReady(); 603 } 604 } 605 } 606 607 /** 608 * Informs CarOemService that ICarImpl's init is complete. 609 */ 610 // This would set mInitComplete, which is an additional check so that no car service component 611 // calls CarOemService during or before ICarImpl's init. 612 @Override onInitComplete()613 public void onInitComplete() { 614 if (!mIsFeatureEnabled) { 615 if (DBG) { 616 Slogf.d(TAG, "Oem Car Service is disabled, No-op for onInitComplete"); 617 } 618 return; 619 } 620 621 synchronized (mLock) { 622 mInitComplete = true; 623 } 624 // inform OEM Service that CarService is ready for communication. 625 // It has to be posted on the different thread as this call is part of init process. 626 mHandler.post(() -> onCarServiceReady()); 627 } 628 629 /** 630 * Gets OEM service latest binder. Don't pass the method to helper as it can cause deadlock. 631 */ getOemService()632 private IOemCarService getOemService() { 633 synchronized (mLock) { 634 return mOemCarService; 635 } 636 } 637 638 private class IOemCarServiceCallbackImpl extends IOemCarServiceCallback.Stub { 639 @Override sendOemCarServiceReady()640 public void sendOemCarServiceReady() { 641 synchronized (mLock) { 642 mIsOemServiceReady = true; 643 } 644 mOemServiceReadyLatch.countDown(); 645 int pid = Binder.getCallingPid(); 646 Slogf.i(TAG, "OEM Car service is ready and running. Process ID of OEM Car Service is:" 647 + " %d", pid); 648 mHelper.updateOemPid(pid); 649 IOemCarService oemCarService = getOemService(); 650 mHelper.updateOemStackCall(() -> oemCarService.getAllStackTraces()); 651 // Initialize other components on handler thread so that main thread is not 652 // blocked 653 mHandler.post(() -> initOemServiceComponents()); 654 } 655 } 656 } 657