1ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung/*
2ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * Copyright (C) 2015 The Android Open Source Project
3ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung *
4ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * Licensed under the Apache License, Version 2.0 (the "License");
5ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * you may not use this file except in compliance with the License.
6ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * You may obtain a copy of the License at
7ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung *
8ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung *      http://www.apache.org/licenses/LICENSE-2.0
9ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung *
10ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * Unless required by applicable law or agreed to in writing, software
11ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * distributed under the License is distributed on an "AS IS" BASIS,
12ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * See the License for the specific language governing permissions and
14ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * limitations under the License.
15ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung */
16bf0eab7a275edfbf7df2881ebca69cde72bd5614Ram Periathiruvadi
17ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungpackage com.android.car;
18ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
190d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsevimport static android.os.SystemClock.elapsedRealtime;
200d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev
210d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsevimport android.annotation.Nullable;
22ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungimport android.app.Service;
23ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungimport android.content.Intent;
24e33f07e7c149ae6bf9154745fd9f83b49127b4f7Yao Chenimport android.content.pm.PackageManager;
25cfe93105f637c2822da113308f113ed418d0b319Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.IVehicle;
26e33f07e7c149ae6bf9154745fd9f83b49127b4f7Yao Chenimport android.os.Binder;
27ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsevimport android.os.Build;
28ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungimport android.os.IBinder;
29ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsevimport android.os.IHwBinder.DeathRecipient;
301552204b9ebedb96dfb44c68ad519ef27c1d3c99Steven Morelandimport android.os.RemoteException;
31b40de197fb9b60bcbb20c243ba6b1a41e25e2e67Steve Paikimport android.os.ServiceManager;
32ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsevimport android.os.SystemClock;
33973d2a26ddab3d7752fa0385da4f53f8f721bfc8Vitalii Tomkivimport android.os.SystemProperties;
34ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungimport android.util.Log;
35ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
36b19bc326413285806ecca7fb7b54ec7a9074f286Enrico Granataimport com.android.car.systeminterface.SystemInterface;
37b19bc326413285806ecca7fb7b54ec7a9074f286Enrico Granata
38ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsevimport com.android.internal.annotations.VisibleForTesting;
39ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsevimport com.android.internal.util.RingBufferIndices;
40ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
41e33f07e7c149ae6bf9154745fd9f83b49127b4f7Yao Chenimport java.io.FileDescriptor;
42e33f07e7c149ae6bf9154745fd9f83b49127b4f7Yao Chenimport java.io.PrintWriter;
43ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsevimport java.util.NoSuchElementException;
44e33f07e7c149ae6bf9154745fd9f83b49127b4f7Yao Chen
45ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungpublic class CarService extends Service {
46ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
470d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    private static final long WAIT_FOR_VEHICLE_HAL_TIMEOUT_MS = 10_000;
480d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev
49ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev    private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
50ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
51ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev    private CanBusErrorNotifier mCanBusErrorNotifier;
52ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    private ICarImpl mICarImpl;
53ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev    private IVehicle mVehicle;
54ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
552cc76d0f8f401f1b62d019da3a9c097c9f52804cPavel Maltsev    private String mVehicleInterfaceName;
562cc76d0f8f401f1b62d019da3a9c097c9f52804cPavel Maltsev
57ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev    // If 10 crashes of Vehicle HAL occurred within 10 minutes then thrown an exception in
58ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev    // Car Service.
59ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev    private final CrashTracker mVhalCrashTracker = new CrashTracker(
60ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            10,  // Max crash count.
61ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            10 * 60 * 1000,  // 10 minutes - sliding time window.
62ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            () -> {
63ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                if (IS_USER_BUILD) {
64ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                    Log.e(CarLog.TAG_SERVICE, "Vehicle HAL keeps crashing, notifying user...");
65ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                    mCanBusErrorNotifier.reportFailure(CarService.this);
66ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                } else {
67ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                    throw new RuntimeException(
68ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                            "Vehicle HAL crashed too many times in a given time frame");
69ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                }
70ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            }
71ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev    );
72ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
73ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev    private final VehicleDeathRecipient mVehicleDeathRecipient = new VehicleDeathRecipient();
74ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
75ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    @Override
76ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    public void onCreate() {
77ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        Log.i(CarLog.TAG_SERVICE, "Service onCreate");
78ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        mCanBusErrorNotifier = new CanBusErrorNotifier(this /* context */);
7999e1a7555a9521c33203b68c5ab5bd1c039ee712Pavel Maltsev        mVehicle = getVehicle();
802cc76d0f8f401f1b62d019da3a9c097c9f52804cPavel Maltsev
81ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        if (mVehicle == null) {
820d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev            throw new IllegalStateException("Vehicle HAL service is not available.");
830d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev        }
842cc76d0f8f401f1b62d019da3a9c097c9f52804cPavel Maltsev        try {
852cc76d0f8f401f1b62d019da3a9c097c9f52804cPavel Maltsev            mVehicleInterfaceName = mVehicle.interfaceDescriptor();
862cc76d0f8f401f1b62d019da3a9c097c9f52804cPavel Maltsev        } catch (RemoteException e) {
872cc76d0f8f401f1b62d019da3a9c097c9f52804cPavel Maltsev            throw new IllegalStateException("Unable to get Vehicle HAL interface descriptor", e);
882cc76d0f8f401f1b62d019da3a9c097c9f52804cPavel Maltsev        }
892cc76d0f8f401f1b62d019da3a9c097c9f52804cPavel Maltsev
902cc76d0f8f401f1b62d019da3a9c097c9f52804cPavel Maltsev        Log.i(CarLog.TAG_SERVICE, "Connected to " + mVehicleInterfaceName);
910d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev
92b19bc326413285806ecca7fb7b54ec7a9074f286Enrico Granata        mICarImpl = new ICarImpl(this,
93b19bc326413285806ecca7fb7b54ec7a9074f286Enrico Granata                mVehicle,
94b19bc326413285806ecca7fb7b54ec7a9074f286Enrico Granata                SystemInterface.Builder.defaultSystemInterface(this).build(),
95e8056ca93515f01f237290bbc371bc082570fa96Enrico Granata                mCanBusErrorNotifier,
96e8056ca93515f01f237290bbc371bc082570fa96Enrico Granata                mVehicleInterfaceName);
970d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev        mICarImpl.init();
98973d2a26ddab3d7752fa0385da4f53f8f721bfc8Vitalii Tomkiv        SystemProperties.set("boot.car_service_created", "1");
99ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
100ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        linkToDeath(mVehicle, mVehicleDeathRecipient);
101ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
102b40de197fb9b60bcbb20c243ba6b1a41e25e2e67Steve Paik        ServiceManager.addService("car_service", mICarImpl);
103ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        super.onCreate();
104ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
105ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
1069a916d707c04d80e9df6dcd84d976900804be717Enrico Granata    // onDestroy is best-effort and might not get called on shutdown/reboot. As such it is not
1079a916d707c04d80e9df6dcd84d976900804be717Enrico Granata    // suitable for permanently saving state or other need-to-happen operation. If you have a
1089a916d707c04d80e9df6dcd84d976900804be717Enrico Granata    // cleanup task that you want to make sure happens on shutdown/reboot, see OnShutdownReboot.
109ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    @Override
110ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    public void onDestroy() {
111ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        Log.i(CarLog.TAG_SERVICE, "Service onDestroy");
1120d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev        mICarImpl.release();
113ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        mCanBusErrorNotifier.removeFailureReport(this);
114ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
115ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        if (mVehicle != null) {
116ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            try {
117ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                mVehicle.unlinkToDeath(mVehicleDeathRecipient);
118ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                mVehicle = null;
119ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            } catch (RemoteException e) {
120ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                // Ignore errors on shutdown path.
121ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            }
122ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        }
123ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
124ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        super.onDestroy();
125ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
126ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
127ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    @Override
128ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    public int onStartCommand(Intent intent, int flags, int startId) {
129ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        // keep it alive.
130ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        return START_STICKY;
131ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
132ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
133ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    @Override
134ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    public IBinder onBind(Intent intent) {
135ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        return mICarImpl;
136ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
137ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
138ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    @Override
139ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
140e8056ca93515f01f237290bbc371bc082570fa96Enrico Granata        // historically, the way to get a dumpsys from CarService has been to use
141e8056ca93515f01f237290bbc371bc082570fa96Enrico Granata        // "dumpsys activity service com.android.car/.CarService" - leaving this
142e8056ca93515f01f237290bbc371bc082570fa96Enrico Granata        // as a forward to car_service makes the previously well-known command still work
143e8056ca93515f01f237290bbc371bc082570fa96Enrico Granata        mICarImpl.dump(fd, writer, args);
144ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
1450d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev
1460d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    @Nullable
14799e1a7555a9521c33203b68c5ab5bd1c039ee712Pavel Maltsev    private IVehicle getVehicleWithTimeout(long waitMilliseconds) {
14899e1a7555a9521c33203b68c5ab5bd1c039ee712Pavel Maltsev        IVehicle vehicle = getVehicle();
1490d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev        long start = elapsedRealtime();
1500d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev        while (vehicle == null && (start + waitMilliseconds) > elapsedRealtime()) {
1510d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev            try {
1520d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev                Thread.sleep(100);
1530d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev            } catch (InterruptedException e) {
1540d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev                throw new RuntimeException("Sleep was interrupted", e);
1550d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev            }
1560d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev
15799e1a7555a9521c33203b68c5ab5bd1c039ee712Pavel Maltsev            vehicle = getVehicle();
1580d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev        }
159ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
160ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        if (vehicle != null) {
161ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            mCanBusErrorNotifier.removeFailureReport(this);
162ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        }
163ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
1640d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev        return vehicle;
1650d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    }
1660d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev
1670d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    @Nullable
16899e1a7555a9521c33203b68c5ab5bd1c039ee712Pavel Maltsev    private static IVehicle getVehicle() {
1691552204b9ebedb96dfb44c68ad519ef27c1d3c99Steven Moreland        try {
17099e1a7555a9521c33203b68c5ab5bd1c039ee712Pavel Maltsev            return android.hardware.automotive.vehicle.V2_0.IVehicle.getService();
1711552204b9ebedb96dfb44c68ad519ef27c1d3c99Steven Moreland        } catch (RemoteException e) {
172ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            Log.e(CarLog.TAG_SERVICE, "Failed to get IVehicle service", e);
173ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        } catch (NoSuchElementException e) {
174ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            Log.e(CarLog.TAG_SERVICE, "IVehicle service not registered yet");
175ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        }
176ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        return null;
177ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev    }
178ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
179ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev    private class VehicleDeathRecipient implements DeathRecipient {
180ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        private int deathCount = 0;
181ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
182ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        @Override
183ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        public void serviceDied(long cookie) {
184ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            Log.w(CarLog.TAG_SERVICE, "Vehicle HAL died.");
185ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
186ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            try {
187ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                mVehicle.unlinkToDeath(this);
188ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            } catch (RemoteException e) {
189ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                Log.e(CarLog.TAG_SERVICE, "Failed to unlinkToDeath", e);  // Log and continue.
190ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            }
191ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            mVehicle = null;
192ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
193ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            mVhalCrashTracker.crashDetected();
194ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
1952cc76d0f8f401f1b62d019da3a9c097c9f52804cPavel Maltsev            Log.i(CarLog.TAG_SERVICE, "Trying to reconnect to Vehicle HAL: " +
1962cc76d0f8f401f1b62d019da3a9c097c9f52804cPavel Maltsev                    mVehicleInterfaceName);
19799e1a7555a9521c33203b68c5ab5bd1c039ee712Pavel Maltsev            mVehicle = getVehicleWithTimeout(WAIT_FOR_VEHICLE_HAL_TIMEOUT_MS);
198ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            if (mVehicle == null) {
199ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                throw new IllegalStateException("Failed to reconnect to Vehicle HAL");
200ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            }
201ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
202ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            linkToDeath(mVehicle, this);
203ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
204ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            Log.i(CarLog.TAG_SERVICE, "Notifying car service Vehicle HAL reconnected...");
205ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            mICarImpl.vehicleHalReconnected(mVehicle);
206ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        }
207ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev    }
208ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
209ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev    private static void linkToDeath(IVehicle vehicle, DeathRecipient recipient) {
210ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        try {
211ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            vehicle.linkToDeath(recipient, 0);
212ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        } catch (RemoteException e) {
213ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            throw new IllegalStateException("Failed to linkToDeath Vehicle HAL");
214ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        }
215ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev    }
216ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
217ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev    @VisibleForTesting
218ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev    static class CrashTracker {
219ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        private final int mMaxCrashCountLimit;
220ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        private final int mSlidingWindowMillis;
221ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
222ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        private final long[] mCrashTimestamps;
223ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        private final RingBufferIndices mCrashTimestampsIndices;
224ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        private final Runnable mCallback;
225ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
226ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        /**
227ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev         * If maxCrashCountLimit number of crashes occurred within slidingWindowMillis time
228ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev         * frame then call provided callback function.
229ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev         */
230ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        CrashTracker(int maxCrashCountLimit, int slidingWindowMillis, Runnable callback) {
231ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            mMaxCrashCountLimit = maxCrashCountLimit;
232ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            mSlidingWindowMillis = slidingWindowMillis;
233ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            mCallback = callback;
234ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
235ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            mCrashTimestamps = new long[maxCrashCountLimit];
236ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            mCrashTimestampsIndices = new RingBufferIndices(mMaxCrashCountLimit);
237ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        }
238ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
239ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev        void crashDetected() {
240ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            long lastCrash = SystemClock.elapsedRealtime();
241ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            mCrashTimestamps[mCrashTimestampsIndices.add()] = lastCrash;
242ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
243ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            if (mCrashTimestampsIndices.size() == mMaxCrashCountLimit) {
244ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                long firstCrash = mCrashTimestamps[mCrashTimestampsIndices.indexOf(0)];
245ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev
246ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                if (lastCrash - firstCrash < mSlidingWindowMillis) {
247ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                    mCallback.run();
248ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev                }
249ec83b63c47f65c5978eec3ee24952969a17b1ee7Pavel Maltsev            }
2501552204b9ebedb96dfb44c68ad519ef27c1d3c99Steven Moreland        }
2510d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    }
252920444970ec041d6b5c886f8d679cda5a3d91eb9Chris Phoenix}
253