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