• 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 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