• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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  */
16 
17 package com.android.car;
18 
19 import static android.os.SystemClock.elapsedRealtime;
20 
21 import android.annotation.Nullable;
22 import android.app.Service;
23 import android.content.Intent;
24 import android.hardware.automotive.vehicle.V2_0.IVehicle;
25 import android.os.Build;
26 import android.os.IBinder;
27 import android.os.IHwBinder.DeathRecipient;
28 import android.os.Process;
29 import android.os.RemoteException;
30 import android.os.ServiceManager;
31 import android.os.SystemClock;
32 import android.os.SystemProperties;
33 import android.os.Trace;
34 import android.util.EventLog;
35 import android.util.Slog;
36 
37 import com.android.car.internal.common.EventLogTags;
38 import com.android.car.systeminterface.SystemInterface;
39 import com.android.car.util.LimitedTimingsTraceLog;
40 import com.android.internal.annotations.VisibleForTesting;
41 import com.android.internal.util.RingBufferIndices;
42 
43 import java.io.FileDescriptor;
44 import java.io.PrintWriter;
45 import java.util.NoSuchElementException;
46 
47 public class CarService extends Service {
48     public static final String CAR_SERVICE_INIT_TIMING_TAG = "CAR.InitTiming";
49     public static final int CAR_SERVICE_INIT_TIMING_MIN_DURATION_MS = 5;
50 
51     private static final boolean RESTART_CAR_SERVICE_WHEN_VHAL_CRASH = true;
52 
53     private static final long WAIT_FOR_VEHICLE_HAL_TIMEOUT_MS = 10_000;
54 
55     private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
56 
57     private ICarImpl mICarImpl;
58     private IVehicle mVehicle;
59 
60     private String mVehicleInterfaceName;
61 
62     private final VehicleDeathRecipient mVehicleDeathRecipient = new VehicleDeathRecipient();
63 
64     @Override
onCreate()65     public void onCreate() {
66         LimitedTimingsTraceLog initTiming = new LimitedTimingsTraceLog(CAR_SERVICE_INIT_TIMING_TAG,
67                 Trace.TRACE_TAG_SYSTEM_SERVER, CAR_SERVICE_INIT_TIMING_MIN_DURATION_MS);
68         initTiming.traceBegin("CarService.onCreate");
69 
70         initTiming.traceBegin("getVehicle");
71         mVehicle = getVehicle();
72         initTiming.traceEnd();
73 
74         EventLog.writeEvent(EventLogTags.CAR_SERVICE_CREATE, mVehicle == null ? 0 : 1);
75 
76         if (mVehicle == null) {
77             throw new IllegalStateException("Vehicle HAL service is not available.");
78         }
79         try {
80             mVehicleInterfaceName = mVehicle.interfaceDescriptor();
81         } catch (RemoteException e) {
82             throw new IllegalStateException("Unable to get Vehicle HAL interface descriptor", e);
83         }
84 
85         Slog.i(CarLog.TAG_SERVICE, "Connected to " + mVehicleInterfaceName);
86         EventLog.writeEvent(EventLogTags.CAR_SERVICE_CONNECTED, mVehicleInterfaceName);
87 
88         mICarImpl = new ICarImpl(this,
89                 mVehicle,
90                 SystemInterface.Builder.defaultSystemInterface(this).build(),
91                 mVehicleInterfaceName);
92         mICarImpl.init();
93 
94         linkToDeath(mVehicle, mVehicleDeathRecipient);
95 
96         ServiceManager.addService("car_service", mICarImpl);
97         SystemProperties.set("boot.car_service_created", "1");
98 
99         super.onCreate();
100 
101         initTiming.traceEnd(); // "CarService.onCreate"
102     }
103 
104     // onDestroy is best-effort and might not get called on shutdown/reboot. As such it is not
105     // suitable for permanently saving state or other need-to-happen operation. If you have a
106     // cleanup task that you want to make sure happens on shutdown/reboot, see OnShutdownReboot.
107     @Override
onDestroy()108     public void onDestroy() {
109         EventLog.writeEvent(EventLogTags.CAR_SERVICE_CREATE, mVehicle == null ? 0 : 1);
110         Slog.i(CarLog.TAG_SERVICE, "Service onDestroy");
111         mICarImpl.release();
112 
113         if (mVehicle != null) {
114             try {
115                 mVehicle.unlinkToDeath(mVehicleDeathRecipient);
116                 mVehicle = null;
117             } catch (RemoteException e) {
118                 // Ignore errors on shutdown path.
119             }
120         }
121 
122         super.onDestroy();
123     }
124 
125     @Override
onStartCommand(Intent intent, int flags, int startId)126     public int onStartCommand(Intent intent, int flags, int startId) {
127         // keep it alive.
128         return START_STICKY;
129     }
130 
131     @Override
onBind(Intent intent)132     public IBinder onBind(Intent intent) {
133         return mICarImpl;
134     }
135 
136     @Override
dump(FileDescriptor fd, PrintWriter writer, String[] args)137     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
138         // historically, the way to get a dumpsys from CarService has been to use
139         // "dumpsys activity service com.android.car/.CarService" - leaving this
140         // as a forward to car_service makes the previously well-known command still work
141         mICarImpl.dump(fd, writer, args);
142     }
143 
144     @Nullable
getVehicleWithTimeout(long waitMilliseconds)145     private IVehicle getVehicleWithTimeout(long waitMilliseconds) {
146         IVehicle vehicle = getVehicle();
147         long start = elapsedRealtime();
148         while (vehicle == null && (start + waitMilliseconds) > elapsedRealtime()) {
149             try {
150                 Thread.sleep(100);
151             } catch (InterruptedException e) {
152                 throw new RuntimeException("Sleep was interrupted", e);
153             }
154 
155             vehicle = getVehicle();
156         }
157 
158         return vehicle;
159     }
160 
161     @Nullable
getVehicle()162     private static IVehicle getVehicle() {
163         final String instanceName = SystemProperties.get("ro.vehicle.hal", "default");
164 
165         try {
166             return android.hardware.automotive.vehicle.V2_0.IVehicle.getService(instanceName);
167         } catch (RemoteException e) {
168             Slog.e(CarLog.TAG_SERVICE, "Failed to get IVehicle/" + instanceName + " service", e);
169         } catch (NoSuchElementException e) {
170             Slog.e(CarLog.TAG_SERVICE, "IVehicle/" + instanceName + " service not registered yet");
171         }
172         return null;
173     }
174 
175     private class VehicleDeathRecipient implements DeathRecipient {
176 
177         @Override
serviceDied(long cookie)178         public void serviceDied(long cookie) {
179             EventLog.writeEvent(EventLogTags.CAR_SERVICE_VHAL_DIED, cookie);
180             Slog.wtf(CarLog.TAG_SERVICE, "***Vehicle HAL died. Car service will restart***");
181             Process.killProcess(Process.myPid());
182         }
183     }
184 
linkToDeath(IVehicle vehicle, DeathRecipient recipient)185     private static void linkToDeath(IVehicle vehicle, DeathRecipient recipient) {
186         try {
187             vehicle.linkToDeath(recipient, 0);
188         } catch (RemoteException e) {
189             throw new IllegalStateException("Failed to linkToDeath Vehicle HAL");
190         }
191     }
192 
193     @VisibleForTesting
194     static class CrashTracker {
195         private final int mMaxCrashCountLimit;
196         private final int mSlidingWindowMillis;
197 
198         private final long[] mCrashTimestamps;
199         private final RingBufferIndices mCrashTimestampsIndices;
200         private final Runnable mCallback;
201 
202         /**
203          * If maxCrashCountLimit number of crashes occurred within slidingWindowMillis time frame
204          * then call provided callback function.
205          */
CrashTracker(int maxCrashCountLimit, int slidingWindowMillis, Runnable callback)206         CrashTracker(int maxCrashCountLimit, int slidingWindowMillis, Runnable callback) {
207             mMaxCrashCountLimit = maxCrashCountLimit;
208             mSlidingWindowMillis = slidingWindowMillis;
209             mCallback = callback;
210 
211             mCrashTimestamps = new long[maxCrashCountLimit];
212             mCrashTimestampsIndices = new RingBufferIndices(mMaxCrashCountLimit);
213         }
214 
crashDetected()215         void crashDetected() {
216             long lastCrash = SystemClock.elapsedRealtime();
217             mCrashTimestamps[mCrashTimestampsIndices.add()] = lastCrash;
218 
219             if (mCrashTimestampsIndices.size() == mMaxCrashCountLimit) {
220                 long firstCrash = mCrashTimestamps[mCrashTimestampsIndices.indexOf(0)];
221 
222                 if (lastCrash - firstCrash < mSlidingWindowMillis) {
223                     mCallback.run();
224                 }
225             }
226         }
227     }
228 }
229