blob: 2d65c0a0736d1b04a06b68329d61af4b67b060dd [file] [log] [blame]
keunyoungca515072015-07-10 12:21:47 -07001/*
2 * Copyright (C) 2015 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 */
16package com.android.car;
17
Pavel Maltsev0d07c762016-11-03 16:40:15 -070018import static android.os.SystemClock.elapsedRealtime;
Pavel Maltsev2cc76d02017-02-14 12:28:33 -080019import static com.android.car.internal.FeatureConfiguration.ENABLE_VEHICLE_HAL_V2_1;
Pavel Maltsev0d07c762016-11-03 16:40:15 -070020
21import android.annotation.Nullable;
keunyoungca515072015-07-10 12:21:47 -070022import android.app.Service;
keunyoungca515072015-07-10 12:21:47 -070023import android.content.Intent;
Yao Chene33f07e2016-07-26 12:02:51 -070024import android.content.pm.PackageManager;
Pavel Maltsevcfe93102017-02-02 12:38:08 -080025import android.hardware.automotive.vehicle.V2_0.IVehicle;
Yao Chene33f07e2016-07-26 12:02:51 -070026import android.os.Binder;
Pavel Maltsevec83b632017-01-05 15:10:55 -080027import android.os.Build;
keunyoungca515072015-07-10 12:21:47 -070028import android.os.IBinder;
Pavel Maltsevec83b632017-01-05 15:10:55 -080029import android.os.IHwBinder.DeathRecipient;
Steven Moreland15522042017-01-05 09:44:59 -080030import android.os.RemoteException;
Pavel Maltsevec83b632017-01-05 15:10:55 -080031import android.os.SystemClock;
Vitalii Tomkiv973d2a22016-04-13 17:05:38 -070032import android.os.SystemProperties;
keunyoungca515072015-07-10 12:21:47 -070033import android.util.Log;
34
Pavel Maltsevec83b632017-01-05 15:10:55 -080035import com.android.internal.annotations.VisibleForTesting;
36import com.android.internal.util.RingBufferIndices;
37
Yao Chene33f07e2016-07-26 12:02:51 -070038import java.io.FileDescriptor;
39import java.io.PrintWriter;
Pavel Maltsevec83b632017-01-05 15:10:55 -080040import java.util.NoSuchElementException;
Yao Chene33f07e2016-07-26 12:02:51 -070041
keunyoungca515072015-07-10 12:21:47 -070042public class CarService extends Service {
43
Pavel Maltsev0d07c762016-11-03 16:40:15 -070044 private static final long WAIT_FOR_VEHICLE_HAL_TIMEOUT_MS = 10_000;
45
Pavel Maltsevec83b632017-01-05 15:10:55 -080046 private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
47
Pavel Maltsev2cc76d02017-02-14 12:28:33 -080048 private static final String IVHAL_20 =
49 android.hardware.automotive.vehicle.V2_0.IVehicle.kInterfaceName;
50 private static final String IVHAL_21 =
51 android.hardware.automotive.vehicle.V2_1.IVehicle.kInterfaceName;
52
Pavel Maltsevec83b632017-01-05 15:10:55 -080053 private CanBusErrorNotifier mCanBusErrorNotifier;
keunyoungca515072015-07-10 12:21:47 -070054 private ICarImpl mICarImpl;
Pavel Maltsevec83b632017-01-05 15:10:55 -080055 private IVehicle mVehicle;
56
Pavel Maltsev2cc76d02017-02-14 12:28:33 -080057 private String mVehicleInterfaceName;
58
Pavel Maltsevec83b632017-01-05 15:10:55 -080059 // If 10 crashes of Vehicle HAL occurred within 10 minutes then thrown an exception in
60 // Car Service.
61 private final CrashTracker mVhalCrashTracker = new CrashTracker(
62 10, // Max crash count.
63 10 * 60 * 1000, // 10 minutes - sliding time window.
64 () -> {
65 if (IS_USER_BUILD) {
66 Log.e(CarLog.TAG_SERVICE, "Vehicle HAL keeps crashing, notifying user...");
67 mCanBusErrorNotifier.reportFailure(CarService.this);
68 } else {
69 throw new RuntimeException(
70 "Vehicle HAL crashed too many times in a given time frame");
71 }
72 }
73 );
74
75 private final VehicleDeathRecipient mVehicleDeathRecipient = new VehicleDeathRecipient();
keunyoungca515072015-07-10 12:21:47 -070076
77 @Override
78 public void onCreate() {
79 Log.i(CarLog.TAG_SERVICE, "Service onCreate");
Pavel Maltsevec83b632017-01-05 15:10:55 -080080 mCanBusErrorNotifier = new CanBusErrorNotifier(this /* context */);
Pavel Maltsev2cc76d02017-02-14 12:28:33 -080081 mVehicle = getVehicle(null /* Any Vehicle HAL interface name */);
82
Pavel Maltsevec83b632017-01-05 15:10:55 -080083 if (mVehicle == null) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -070084 throw new IllegalStateException("Vehicle HAL service is not available.");
85 }
Pavel Maltsev2cc76d02017-02-14 12:28:33 -080086 try {
87 mVehicleInterfaceName = mVehicle.interfaceDescriptor();
88 } catch (RemoteException e) {
89 throw new IllegalStateException("Unable to get Vehicle HAL interface descriptor", e);
90 }
91
92 Log.i(CarLog.TAG_SERVICE, "Connected to " + mVehicleInterfaceName);
Pavel Maltsev0d07c762016-11-03 16:40:15 -070093
Pavel Maltsevec83b632017-01-05 15:10:55 -080094 mICarImpl = new ICarImpl(this, mVehicle, SystemInterface.getDefault(this),
95 mCanBusErrorNotifier);
Pavel Maltsev0d07c762016-11-03 16:40:15 -070096 mICarImpl.init();
Vitalii Tomkiv973d2a22016-04-13 17:05:38 -070097 SystemProperties.set("boot.car_service_created", "1");
Pavel Maltsevec83b632017-01-05 15:10:55 -080098
99 linkToDeath(mVehicle, mVehicleDeathRecipient);
100
keunyoungca515072015-07-10 12:21:47 -0700101 super.onCreate();
102 }
103
104 @Override
105 public void onDestroy() {
106 Log.i(CarLog.TAG_SERVICE, "Service onDestroy");
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700107 mICarImpl.release();
Pavel Maltsevec83b632017-01-05 15:10:55 -0800108 mCanBusErrorNotifier.removeFailureReport(this);
109
110 if (mVehicle != null) {
111 try {
112 mVehicle.unlinkToDeath(mVehicleDeathRecipient);
113 mVehicle = null;
114 } catch (RemoteException e) {
115 // Ignore errors on shutdown path.
116 }
117 }
118
keunyoungca515072015-07-10 12:21:47 -0700119 super.onDestroy();
120 }
121
122 @Override
123 public int onStartCommand(Intent intent, int flags, int startId) {
124 // keep it alive.
125 return START_STICKY;
126 }
127
128 @Override
129 public IBinder onBind(Intent intent) {
130 return mICarImpl;
131 }
132
133 @Override
134 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
Yao Chene33f07e2016-07-26 12:02:51 -0700135 if (checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
136 != PackageManager.PERMISSION_GRANTED) {
137 writer.println("Permission Denial: can't dump CarService from from pid="
138 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
139 + " without permission " + android.Manifest.permission.DUMP);
140 return;
141 }
142 if (args == null || args.length == 0) {
143 writer.println("*dump car service*");
Pavel Maltsev2cc76d02017-02-14 12:28:33 -0800144 writer.println("Vehicle HAL Interface: " + mVehicleInterfaceName);
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700145 mICarImpl.dump(writer);
Pavel Maltsevec83b632017-01-05 15:10:55 -0800146
147 writer.println("**Debug info**");
148 writer.println("Vehicle HAL reconnected: "
149 + mVehicleDeathRecipient.deathCount + " times.");
Yao Chene33f07e2016-07-26 12:02:51 -0700150 } else {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700151 mICarImpl.execShellCmd(args, writer);
Yao Chene33f07e2016-07-26 12:02:51 -0700152 }
keunyoungca515072015-07-10 12:21:47 -0700153 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700154
155 @Nullable
Pavel Maltsev2cc76d02017-02-14 12:28:33 -0800156 private IVehicle getVehicleWithTimeout(long waitMilliseconds, @Nullable String interfaceName) {
157 IVehicle vehicle = getVehicle(interfaceName);
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700158 long start = elapsedRealtime();
159 while (vehicle == null && (start + waitMilliseconds) > elapsedRealtime()) {
160 try {
161 Thread.sleep(100);
162 } catch (InterruptedException e) {
163 throw new RuntimeException("Sleep was interrupted", e);
164 }
165
Pavel Maltsev2cc76d02017-02-14 12:28:33 -0800166 vehicle = getVehicle(interfaceName);
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700167 }
Pavel Maltsevec83b632017-01-05 15:10:55 -0800168
169 if (vehicle != null) {
170 mCanBusErrorNotifier.removeFailureReport(this);
171 }
172
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700173 return vehicle;
174 }
175
176 @Nullable
Pavel Maltsev2cc76d02017-02-14 12:28:33 -0800177 private static IVehicle getVehicle(@Nullable String interfaceName) {
Steven Moreland15522042017-01-05 09:44:59 -0800178 try {
Pavel Maltsev2cc76d02017-02-14 12:28:33 -0800179 boolean anyVersion = interfaceName == null || interfaceName.isEmpty();
180 IVehicle vehicle = null;
181 if (ENABLE_VEHICLE_HAL_V2_1 && (anyVersion || IVHAL_21.equals(interfaceName))) {
182 vehicle = android.hardware.automotive.vehicle.V2_1.IVehicle
Chris Phoenix92044492017-01-11 18:36:39 -0800183 .getService();
Pavel Maltsev2cc76d02017-02-14 12:28:33 -0800184 }
185
186 if (vehicle == null && (anyVersion || IVHAL_20.equals(interfaceName))) {
187 vehicle = android.hardware.automotive.vehicle.V2_0.IVehicle
Chris Phoenix92044492017-01-11 18:36:39 -0800188 .getService();
Pavel Maltsev2cc76d02017-02-14 12:28:33 -0800189 }
190 return vehicle;
Steven Moreland15522042017-01-05 09:44:59 -0800191 } catch (RemoteException e) {
Pavel Maltsevec83b632017-01-05 15:10:55 -0800192 Log.e(CarLog.TAG_SERVICE, "Failed to get IVehicle service", e);
193 } catch (NoSuchElementException e) {
194 Log.e(CarLog.TAG_SERVICE, "IVehicle service not registered yet");
195 }
196 return null;
197 }
198
199 private class VehicleDeathRecipient implements DeathRecipient {
200 private int deathCount = 0;
201
202 @Override
203 public void serviceDied(long cookie) {
204 Log.w(CarLog.TAG_SERVICE, "Vehicle HAL died.");
205
206 try {
207 mVehicle.unlinkToDeath(this);
208 } catch (RemoteException e) {
209 Log.e(CarLog.TAG_SERVICE, "Failed to unlinkToDeath", e); // Log and continue.
210 }
211 mVehicle = null;
212
213 mVhalCrashTracker.crashDetected();
214
Pavel Maltsev2cc76d02017-02-14 12:28:33 -0800215 Log.i(CarLog.TAG_SERVICE, "Trying to reconnect to Vehicle HAL: " +
216 mVehicleInterfaceName);
217 mVehicle = getVehicleWithTimeout(WAIT_FOR_VEHICLE_HAL_TIMEOUT_MS,
218 mVehicleInterfaceName);
Pavel Maltsevec83b632017-01-05 15:10:55 -0800219 if (mVehicle == null) {
220 throw new IllegalStateException("Failed to reconnect to Vehicle HAL");
221 }
222
223 linkToDeath(mVehicle, this);
224
225 Log.i(CarLog.TAG_SERVICE, "Notifying car service Vehicle HAL reconnected...");
226 mICarImpl.vehicleHalReconnected(mVehicle);
227 }
228 }
229
230 private static void linkToDeath(IVehicle vehicle, DeathRecipient recipient) {
231 try {
232 vehicle.linkToDeath(recipient, 0);
233 } catch (RemoteException e) {
234 throw new IllegalStateException("Failed to linkToDeath Vehicle HAL");
235 }
236 }
237
238 @VisibleForTesting
239 static class CrashTracker {
240 private final int mMaxCrashCountLimit;
241 private final int mSlidingWindowMillis;
242
243 private final long[] mCrashTimestamps;
244 private final RingBufferIndices mCrashTimestampsIndices;
245 private final Runnable mCallback;
246
247 /**
248 * If maxCrashCountLimit number of crashes occurred within slidingWindowMillis time
249 * frame then call provided callback function.
250 */
251 CrashTracker(int maxCrashCountLimit, int slidingWindowMillis, Runnable callback) {
252 mMaxCrashCountLimit = maxCrashCountLimit;
253 mSlidingWindowMillis = slidingWindowMillis;
254 mCallback = callback;
255
256 mCrashTimestamps = new long[maxCrashCountLimit];
257 mCrashTimestampsIndices = new RingBufferIndices(mMaxCrashCountLimit);
258 }
259
260 void crashDetected() {
261 long lastCrash = SystemClock.elapsedRealtime();
262 mCrashTimestamps[mCrashTimestampsIndices.add()] = lastCrash;
263
264 if (mCrashTimestampsIndices.size() == mMaxCrashCountLimit) {
265 long firstCrash = mCrashTimestamps[mCrashTimestampsIndices.indexOf(0)];
266
267 if (lastCrash - firstCrash < mSlidingWindowMillis) {
268 mCallback.run();
269 }
270 }
Steven Moreland15522042017-01-05 09:44:59 -0800271 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700272 }
Chris Phoenix92044492017-01-11 18:36:39 -0800273}