diff options
author | Gregory Clark | 2018-06-07 18:42:12 -0500 |
---|---|---|
committer | Gregory Clark | 2018-06-19 20:19:16 -0500 |
commit | a63ba02a9279dc55cc3ef77dbec02c54383afdbe (patch) | |
tree | 0352b73e396f1a47b5eabd58cbd93decce1302ec /service | |
parent | cf6d16cbadc4916e67c60573178791cf25b3ff09 (diff) | |
download | platform-packages-services-car-a63ba02a9279dc55cc3ef77dbec02c54383afdbe.tar.gz platform-packages-services-car-a63ba02a9279dc55cc3ef77dbec02c54383afdbe.tar.xz platform-packages-services-car-a63ba02a9279dc55cc3ef77dbec02c54383afdbe.zip |
Update the CarLocationService to work when the system user is headless.
Bug: b/79772231
Test: Tested on Owl and ran atest CarLocationServiceTest
Change-Id: I1598f0fba0ba5335cb1d9c81e16d1db8d7922df0
Diffstat (limited to 'service')
-rw-r--r-- | service/src/com/android/car/CarLocationService.java | 188 | ||||
-rw-r--r-- | service/src/com/android/car/ICarImpl.java | 6 |
2 files changed, 127 insertions, 67 deletions
diff --git a/service/src/com/android/car/CarLocationService.java b/service/src/com/android/car/CarLocationService.java index 6d93b40c..a7aaf035 100644 --- a/service/src/com/android/car/CarLocationService.java +++ b/service/src/com/android/car/CarLocationService.java | |||
@@ -19,6 +19,7 @@ package com.android.car; | |||
19 | import android.car.hardware.CarPropertyValue; | 19 | import android.car.hardware.CarPropertyValue; |
20 | import android.car.hardware.property.CarPropertyEvent; | 20 | import android.car.hardware.property.CarPropertyEvent; |
21 | import android.car.hardware.property.ICarPropertyEventListener; | 21 | import android.car.hardware.property.ICarPropertyEventListener; |
22 | import android.car.user.CarUserManagerHelper; | ||
22 | import android.content.BroadcastReceiver; | 23 | import android.content.BroadcastReceiver; |
23 | import android.content.Context; | 24 | import android.content.Context; |
24 | import android.content.Intent; | 25 | import android.content.Intent; |
@@ -31,6 +32,7 @@ import android.os.Handler; | |||
31 | import android.os.HandlerThread; | 32 | import android.os.HandlerThread; |
32 | import android.os.RemoteException; | 33 | import android.os.RemoteException; |
33 | import android.os.SystemClock; | 34 | import android.os.SystemClock; |
35 | import android.os.UserHandle; | ||
34 | import android.util.AtomicFile; | 36 | import android.util.AtomicFile; |
35 | import android.util.JsonReader; | 37 | import android.util.JsonReader; |
36 | import android.util.JsonWriter; | 38 | import android.util.JsonWriter; |
@@ -60,6 +62,8 @@ public class CarLocationService extends BroadcastReceiver implements CarServiceB | |||
60 | private static final long GRANULARITY_ONE_DAY_MS = 24 * 60 * 60 * 1000L; | 62 | private static final long GRANULARITY_ONE_DAY_MS = 24 * 60 * 60 * 1000L; |
61 | // The time-to-live for the cached location | 63 | // The time-to-live for the cached location |
62 | private static final long TTL_THIRTY_DAYS_MS = 30 * GRANULARITY_ONE_DAY_MS; | 64 | private static final long TTL_THIRTY_DAYS_MS = 30 * GRANULARITY_ONE_DAY_MS; |
65 | // The maximum number of times to try injecting a location | ||
66 | private static final int MAX_LOCATION_INJECTION_ATTEMPTS = 10; | ||
63 | 67 | ||
64 | // Used internally for mHandlerThread synchronization | 68 | // Used internally for mHandlerThread synchronization |
65 | private final Object mLock = new Object(); | 69 | private final Object mLock = new Object(); |
@@ -68,23 +72,26 @@ public class CarLocationService extends BroadcastReceiver implements CarServiceB | |||
68 | private final CarPowerManagementService mCarPowerManagementService; | 72 | private final CarPowerManagementService mCarPowerManagementService; |
69 | private final CarPropertyService mCarPropertyService; | 73 | private final CarPropertyService mCarPropertyService; |
70 | private final CarPropertyEventListener mCarPropertyEventListener; | 74 | private final CarPropertyEventListener mCarPropertyEventListener; |
75 | private final CarUserManagerHelper mCarUserManagerHelper; | ||
71 | private int mTaskCount = 0; | 76 | private int mTaskCount = 0; |
72 | private HandlerThread mHandlerThread; | 77 | private HandlerThread mHandlerThread; |
73 | private Handler mHandler; | 78 | private Handler mHandler; |
74 | 79 | ||
75 | public CarLocationService(Context context, CarPowerManagementService carPowerManagementService, | 80 | public CarLocationService(Context context, CarPowerManagementService carPowerManagementService, |
76 | CarPropertyService carPropertyService) { | 81 | CarPropertyService carPropertyService, CarUserManagerHelper carUserManagerHelper) { |
77 | logd("constructed"); | 82 | logd("constructed"); |
78 | mContext = context; | 83 | mContext = context; |
79 | mCarPowerManagementService = carPowerManagementService; | 84 | mCarPowerManagementService = carPowerManagementService; |
80 | mCarPropertyService = carPropertyService; | 85 | mCarPropertyService = carPropertyService; |
81 | mCarPropertyEventListener = new CarPropertyEventListener(); | 86 | mCarPropertyEventListener = new CarPropertyEventListener(); |
87 | mCarUserManagerHelper = carUserManagerHelper; | ||
82 | } | 88 | } |
83 | 89 | ||
84 | @Override | 90 | @Override |
85 | public void init() { | 91 | public void init() { |
86 | logd("init"); | 92 | logd("init"); |
87 | IntentFilter filter = new IntentFilter(); | 93 | IntentFilter filter = new IntentFilter(); |
94 | filter.addAction(Intent.ACTION_USER_SWITCHED); | ||
88 | filter.addAction(Intent.ACTION_LOCKED_BOOT_COMPLETED); | 95 | filter.addAction(Intent.ACTION_LOCKED_BOOT_COMPLETED); |
89 | filter.addAction(LocationManager.MODE_CHANGED_ACTION); | 96 | filter.addAction(LocationManager.MODE_CHANGED_ACTION); |
90 | filter.addAction(LocationManager.GPS_ENABLED_CHANGE_ACTION); | 97 | filter.addAction(LocationManager.GPS_ENABLED_CHANGE_ACTION); |
@@ -107,17 +114,19 @@ public class CarLocationService extends BroadcastReceiver implements CarServiceB | |||
107 | writer.println(TAG); | 114 | writer.println(TAG); |
108 | writer.println("Context: " + mContext); | 115 | writer.println("Context: " + mContext); |
109 | writer.println("CarPropertyService: " + mCarPropertyService); | 116 | writer.println("CarPropertyService: " + mCarPropertyService); |
117 | writer.println("MAX_LOCATION_INJECTION_ATTEMPTS: " + MAX_LOCATION_INJECTION_ATTEMPTS); | ||
110 | } | 118 | } |
111 | 119 | ||
112 | @Override | 120 | @Override |
113 | public long onPrepareShutdown(boolean shuttingDown) { | 121 | public long onPrepareShutdown(boolean shuttingDown) { |
114 | logd("onPrepareShutdown " + shuttingDown); | 122 | logd("onPrepareShutdown " + shuttingDown); |
115 | asyncOperation(() -> storeLocation()); | 123 | asyncOperation(() -> storeLocation()); |
116 | return 0; | 124 | return 100; |
117 | } | 125 | } |
118 | 126 | ||
119 | @Override | 127 | @Override |
120 | public void onPowerOn(boolean displayOn) { } | 128 | public void onPowerOn(boolean displayOn) { |
129 | } | ||
121 | 130 | ||
122 | @Override | 131 | @Override |
123 | public int getWakeupTime() { | 132 | public int getWakeupTime() { |
@@ -129,27 +138,55 @@ public class CarLocationService extends BroadcastReceiver implements CarServiceB | |||
129 | logd("onReceive " + intent); | 138 | logd("onReceive " + intent); |
130 | String action = intent.getAction(); | 139 | String action = intent.getAction(); |
131 | if (action == Intent.ACTION_LOCKED_BOOT_COMPLETED) { | 140 | if (action == Intent.ACTION_LOCKED_BOOT_COMPLETED) { |
132 | asyncOperation(() -> loadLocation()); | 141 | // If the system user is not headless, then we can inject location as soon as the |
133 | } else { | 142 | // system has completed booting. |
143 | if (!mCarUserManagerHelper.isHeadlessSystemUser()) { | ||
144 | logd("not headless on boot complete"); | ||
145 | asyncOperation(() -> loadLocation()); | ||
146 | } | ||
147 | } else if (action == Intent.ACTION_USER_SWITCHED) { | ||
148 | int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); | ||
149 | logd("USER_SWITCHED: " + userHandle); | ||
150 | if (mCarUserManagerHelper.isHeadlessSystemUser() | ||
151 | && userHandle > UserHandle.USER_SYSTEM) { | ||
152 | asyncOperation(() -> loadLocation()); | ||
153 | } | ||
154 | } else if (action == LocationManager.MODE_CHANGED_ACTION | ||
155 | && shouldCheckLocationPermissions()) { | ||
134 | LocationManager locationManager = | 156 | LocationManager locationManager = |
135 | (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); | 157 | (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); |
136 | if (action == LocationManager.MODE_CHANGED_ACTION) { | 158 | boolean locationEnabled = locationManager.isLocationEnabled(); |
137 | boolean locationEnabled = locationManager.isLocationEnabled(); | 159 | logd("isLocationEnabled(): " + locationEnabled); |
138 | logd("isLocationEnabled(): " + locationEnabled); | 160 | if (!locationEnabled) { |
139 | if (!locationEnabled) { | 161 | asyncOperation(() -> deleteCacheFile()); |
140 | asyncOperation(() -> deleteCacheFile()); | 162 | } |
141 | } | 163 | } else if (action == LocationManager.GPS_ENABLED_CHANGE_ACTION |
142 | } else if (action == LocationManager.GPS_ENABLED_CHANGE_ACTION) { | 164 | && shouldCheckLocationPermissions()) { |
143 | boolean gpsEnabled = | 165 | LocationManager locationManager = |
144 | locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); | 166 | (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); |
145 | logd("isProviderEnabled('gps'): " + gpsEnabled); | 167 | boolean gpsEnabled = |
146 | if (!gpsEnabled) { | 168 | locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); |
147 | asyncOperation(() -> deleteCacheFile()); | 169 | logd("isProviderEnabled('gps'): " + gpsEnabled); |
148 | } | 170 | if (!gpsEnabled) { |
171 | asyncOperation(() -> deleteCacheFile()); | ||
149 | } | 172 | } |
150 | } | 173 | } |
151 | } | 174 | } |
152 | 175 | ||
176 | /** | ||
177 | * Tells whether or not we should check location permissions for the sake of deleting the | ||
178 | * location cache file when permissions are lacking. If the system user is headless but the | ||
179 | * current user is still the system user, then we should not respond to a lack of location | ||
180 | * permissions. | ||
181 | */ | ||
182 | private boolean shouldCheckLocationPermissions() { | ||
183 | return !(mCarUserManagerHelper.isHeadlessSystemUser() | ||
184 | && mCarUserManagerHelper.isCurrentProcessSystemUser()); | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * Gets the last known location from the LocationManager and store it in a file. | ||
189 | */ | ||
153 | private void storeLocation() { | 190 | private void storeLocation() { |
154 | LocationManager locationManager = | 191 | LocationManager locationManager = |
155 | (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); | 192 | (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); |
@@ -163,44 +200,44 @@ public class CarLocationService extends BroadcastReceiver implements CarServiceB | |||
163 | FileOutputStream fos = null; | 200 | FileOutputStream fos = null; |
164 | try { | 201 | try { |
165 | fos = atomicFile.startWrite(); | 202 | fos = atomicFile.startWrite(); |
166 | JsonWriter jsonWriter = new JsonWriter(new OutputStreamWriter(fos, "UTF-8")); | 203 | try (JsonWriter jsonWriter = new JsonWriter(new OutputStreamWriter(fos, "UTF-8"))) { |
167 | jsonWriter.beginObject(); | 204 | jsonWriter.beginObject(); |
168 | jsonWriter.name("provider").value(location.getProvider()); | 205 | jsonWriter.name("provider").value(location.getProvider()); |
169 | jsonWriter.name("latitude").value(location.getLatitude()); | 206 | jsonWriter.name("latitude").value(location.getLatitude()); |
170 | jsonWriter.name("longitude").value(location.getLongitude()); | 207 | jsonWriter.name("longitude").value(location.getLongitude()); |
171 | if (location.hasAltitude()) { | 208 | if (location.hasAltitude()) { |
172 | jsonWriter.name("altitude").value(location.getAltitude()); | 209 | jsonWriter.name("altitude").value(location.getAltitude()); |
173 | } | 210 | } |
174 | if (location.hasSpeed()) { | 211 | if (location.hasSpeed()) { |
175 | jsonWriter.name("speed").value(location.getSpeed()); | 212 | jsonWriter.name("speed").value(location.getSpeed()); |
176 | } | 213 | } |
177 | if (location.hasBearing()) { | 214 | if (location.hasBearing()) { |
178 | jsonWriter.name("bearing").value(location.getBearing()); | 215 | jsonWriter.name("bearing").value(location.getBearing()); |
179 | } | 216 | } |
180 | if (location.hasAccuracy()) { | 217 | if (location.hasAccuracy()) { |
181 | jsonWriter.name("accuracy").value(location.getAccuracy()); | 218 | jsonWriter.name("accuracy").value(location.getAccuracy()); |
182 | } | 219 | } |
183 | if (location.hasVerticalAccuracy()) { | 220 | if (location.hasVerticalAccuracy()) { |
184 | jsonWriter.name("verticalAccuracy").value( | 221 | jsonWriter.name("verticalAccuracy").value( |
185 | location.getVerticalAccuracyMeters()); | 222 | location.getVerticalAccuracyMeters()); |
186 | } | 223 | } |
187 | if (location.hasSpeedAccuracy()) { | 224 | if (location.hasSpeedAccuracy()) { |
188 | jsonWriter.name("speedAccuracy").value( | 225 | jsonWriter.name("speedAccuracy").value( |
189 | location.getSpeedAccuracyMetersPerSecond()); | 226 | location.getSpeedAccuracyMetersPerSecond()); |
190 | } | 227 | } |
191 | if (location.hasBearingAccuracy()) { | 228 | if (location.hasBearingAccuracy()) { |
192 | jsonWriter.name("bearingAccuracy").value( | 229 | jsonWriter.name("bearingAccuracy").value( |
193 | location.getBearingAccuracyDegrees()); | 230 | location.getBearingAccuracyDegrees()); |
194 | } | 231 | } |
195 | if (location.isFromMockProvider()) { | 232 | if (location.isFromMockProvider()) { |
196 | jsonWriter.name("isFromMockProvider").value(true); | 233 | jsonWriter.name("isFromMockProvider").value(true); |
234 | } | ||
235 | long currentTime = location.getTime(); | ||
236 | // Round the time down to only be accurate within one day. | ||
237 | jsonWriter.name("captureTime").value( | ||
238 | currentTime - currentTime % GRANULARITY_ONE_DAY_MS); | ||
239 | jsonWriter.endObject(); | ||
197 | } | 240 | } |
198 | long currentTime = location.getTime(); | ||
199 | // Round the time down to only be accurate within one day. | ||
200 | jsonWriter.name("captureTime").value( | ||
201 | currentTime - currentTime % GRANULARITY_ONE_DAY_MS); | ||
202 | jsonWriter.endObject(); | ||
203 | jsonWriter.close(); | ||
204 | atomicFile.finishWrite(fos); | 241 | atomicFile.finishWrite(fos); |
205 | } catch (IOException e) { | 242 | } catch (IOException e) { |
206 | Log.e(TAG, "Unable to write to disk", e); | 243 | Log.e(TAG, "Unable to write to disk", e); |
@@ -209,6 +246,9 @@ public class CarLocationService extends BroadcastReceiver implements CarServiceB | |||
209 | } | 246 | } |
210 | } | 247 | } |
211 | 248 | ||
249 | /** | ||
250 | * Reads a previously stored location and attempts to inject it into the LocationManager. | ||
251 | */ | ||
212 | private void loadLocation() { | 252 | private void loadLocation() { |
213 | Location location = readLocationFromCacheFile(); | 253 | Location location = readLocationFromCacheFile(); |
214 | logd("Read location from " + location.getTime()); | 254 | logd("Read location from " + location.getTime()); |
@@ -220,10 +260,7 @@ public class CarLocationService extends BroadcastReceiver implements CarServiceB | |||
220 | long elapsedTime = SystemClock.elapsedRealtimeNanos(); | 260 | long elapsedTime = SystemClock.elapsedRealtimeNanos(); |
221 | location.setElapsedRealtimeNanos(elapsedTime); | 261 | location.setElapsedRealtimeNanos(elapsedTime); |
222 | if (location.isComplete()) { | 262 | if (location.isComplete()) { |
223 | LocationManager locationManager = | 263 | injectLocation(location, 1); |
224 | (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); | ||
225 | boolean success = locationManager.injectLocation(location); | ||
226 | logd("Injected location " + location + " with result " + success); | ||
227 | } | 264 | } |
228 | } | 265 | } |
229 | } | 266 | } |
@@ -231,8 +268,7 @@ public class CarLocationService extends BroadcastReceiver implements CarServiceB | |||
231 | private Location readLocationFromCacheFile() { | 268 | private Location readLocationFromCacheFile() { |
232 | Location location = new Location((String) null); | 269 | Location location = new Location((String) null); |
233 | AtomicFile atomicFile = new AtomicFile(mContext.getFileStreamPath(FILENAME)); | 270 | AtomicFile atomicFile = new AtomicFile(mContext.getFileStreamPath(FILENAME)); |
234 | try { | 271 | try (FileInputStream fis = atomicFile.openRead()) { |
235 | FileInputStream fis = atomicFile.openRead(); | ||
236 | JsonReader reader = new JsonReader(new InputStreamReader(fis, "UTF-8")); | 272 | JsonReader reader = new JsonReader(new InputStreamReader(fis, "UTF-8")); |
237 | reader.beginObject(); | 273 | reader.beginObject(); |
238 | while (reader.hasNext()) { | 274 | while (reader.hasNext()) { |
@@ -266,7 +302,6 @@ public class CarLocationService extends BroadcastReceiver implements CarServiceB | |||
266 | } | 302 | } |
267 | } | 303 | } |
268 | reader.endObject(); | 304 | reader.endObject(); |
269 | fis.close(); | ||
270 | deleteCacheFile(); | 305 | deleteCacheFile(); |
271 | } catch (FileNotFoundException e) { | 306 | } catch (FileNotFoundException e) { |
272 | Log.d(TAG, "Location cache file not found."); | 307 | Log.d(TAG, "Location cache file not found."); |
@@ -283,8 +318,33 @@ public class CarLocationService extends BroadcastReceiver implements CarServiceB | |||
283 | mContext.deleteFile(FILENAME); | 318 | mContext.deleteFile(FILENAME); |
284 | } | 319 | } |
285 | 320 | ||
321 | /** | ||
322 | * Attempts to inject the location multiple times in case the LocationManager was not fully | ||
323 | * initialized or has not updated its handle to the current user yet. | ||
324 | */ | ||
325 | private void injectLocation(Location location, int attemptCount) { | ||
326 | LocationManager locationManager = | ||
327 | (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); | ||
328 | boolean success = locationManager.injectLocation(location); | ||
329 | logd("Injected location " + location + " with result " + success + " on attempt " | ||
330 | + attemptCount); | ||
331 | if (success) { | ||
332 | return; | ||
333 | } else if (attemptCount <= MAX_LOCATION_INJECTION_ATTEMPTS) { | ||
334 | asyncOperation(() -> { | ||
335 | injectLocation(location, attemptCount + 1); | ||
336 | }, 200 * attemptCount); | ||
337 | } else { | ||
338 | logd("No location injected."); | ||
339 | } | ||
340 | } | ||
341 | |||
286 | @VisibleForTesting | 342 | @VisibleForTesting |
287 | void asyncOperation(Runnable operation) { | 343 | void asyncOperation(Runnable operation) { |
344 | asyncOperation(operation, 0); | ||
345 | } | ||
346 | |||
347 | private void asyncOperation(Runnable operation, long delayMillis) { | ||
288 | synchronized (mLock) { | 348 | synchronized (mLock) { |
289 | // Create a new HandlerThread if this is the first task to queue. | 349 | // Create a new HandlerThread if this is the first task to queue. |
290 | if (++mTaskCount == 1) { | 350 | if (++mTaskCount == 1) { |
@@ -293,7 +353,7 @@ public class CarLocationService extends BroadcastReceiver implements CarServiceB | |||
293 | mHandler = new Handler(mHandlerThread.getLooper()); | 353 | mHandler = new Handler(mHandlerThread.getLooper()); |
294 | } | 354 | } |
295 | } | 355 | } |
296 | mHandler.post(() -> { | 356 | mHandler.postDelayed(() -> { |
297 | try { | 357 | try { |
298 | operation.run(); | 358 | operation.run(); |
299 | } finally { | 359 | } finally { |
@@ -306,7 +366,7 @@ public class CarLocationService extends BroadcastReceiver implements CarServiceB | |||
306 | } | 366 | } |
307 | } | 367 | } |
308 | } | 368 | } |
309 | }); | 369 | }, delayMillis); |
310 | } | 370 | } |
311 | 371 | ||
312 | private static void logd(String msg) { | 372 | private static void logd(String msg) { |
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java index 9a15631a..67c50a75 100644 --- a/service/src/com/android/car/ICarImpl.java +++ b/service/src/com/android/car/ICarImpl.java | |||
@@ -123,8 +123,6 @@ public class ICarImpl extends ICar.Stub { | |||
123 | mCarInputService = new CarInputService(serviceContext, mHal.getInputHal()); | 123 | mCarInputService = new CarInputService(serviceContext, mHal.getInputHal()); |
124 | mCarProjectionService = new CarProjectionService(serviceContext, mCarInputService); | 124 | mCarProjectionService = new CarProjectionService(serviceContext, mCarInputService); |
125 | mGarageModeService = new GarageModeService(mContext, mCarPowerManagementService); | 125 | mGarageModeService = new GarageModeService(mContext, mCarPowerManagementService); |
126 | mCarLocationService = new CarLocationService(mContext, mCarPowerManagementService, | ||
127 | mCarPropertyService); | ||
128 | mAppFocusService = new AppFocusService(serviceContext, mSystemActivityMonitoringService); | 126 | mAppFocusService = new AppFocusService(serviceContext, mSystemActivityMonitoringService); |
129 | mCarAudioService = new CarAudioService(serviceContext); | 127 | mCarAudioService = new CarAudioService(serviceContext); |
130 | mCarNightService = new CarNightService(serviceContext, mCarPropertyService); | 128 | mCarNightService = new CarNightService(serviceContext, mCarPropertyService); |
@@ -143,6 +141,8 @@ public class ICarImpl extends ICar.Stub { | |||
143 | mCarConfigurationService = | 141 | mCarConfigurationService = |
144 | new CarConfigurationService(serviceContext, new JsonReaderImpl()); | 142 | new CarConfigurationService(serviceContext, new JsonReaderImpl()); |
145 | mUserManagerHelper = new CarUserManagerHelper(serviceContext); | 143 | mUserManagerHelper = new CarUserManagerHelper(serviceContext); |
144 | mCarLocationService = new CarLocationService(mContext, mCarPowerManagementService, | ||
145 | mCarPropertyService, mUserManagerHelper); | ||
146 | 146 | ||
147 | // Be careful with order. Service depending on other service should be inited later. | 147 | // Be careful with order. Service depending on other service should be inited later. |
148 | List<CarServiceBase> allServices = new ArrayList<>(); | 148 | List<CarServiceBase> allServices = new ArrayList<>(); |
@@ -153,7 +153,6 @@ public class ICarImpl extends ICar.Stub { | |||
153 | allServices.add(mCarUXRestrictionsService); | 153 | allServices.add(mCarUXRestrictionsService); |
154 | allServices.add(mCarPackageManagerService); | 154 | allServices.add(mCarPackageManagerService); |
155 | allServices.add(mCarInputService); | 155 | allServices.add(mCarInputService); |
156 | allServices.add(mCarLocationService); | ||
157 | allServices.add(mGarageModeService); | 156 | allServices.add(mGarageModeService); |
158 | allServices.add(mAppFocusService); | 157 | allServices.add(mAppFocusService); |
159 | allServices.add(mCarAudioService); | 158 | allServices.add(mCarAudioService); |
@@ -174,6 +173,7 @@ public class ICarImpl extends ICar.Stub { | |||
174 | allServices.add(mCarUserService); | 173 | allServices.add(mCarUserService); |
175 | } | 174 | } |
176 | 175 | ||
176 | allServices.add(mCarLocationService); | ||
177 | mAllServices = allServices.toArray(new CarServiceBase[allServices.size()]); | 177 | mAllServices = allServices.toArray(new CarServiceBase[allServices.size()]); |
178 | } | 178 | } |
179 | 179 | ||