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