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