1 /* 2 * Copyright (C) 2009 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.server.location; 18 19 import java.io.FileDescriptor; 20 import java.io.PrintWriter; 21 import java.util.List; 22 23 import android.content.Context; 24 import android.location.LocationProvider; 25 import android.os.Bundle; 26 import android.os.Handler; 27 import android.os.RemoteException; 28 import android.os.WorkSource; 29 import android.util.Log; 30 31 import com.android.internal.location.ProviderProperties; 32 import com.android.internal.location.ILocationProvider; 33 import com.android.internal.location.ProviderRequest; 34 import com.android.server.LocationManagerService; 35 import com.android.server.ServiceWatcher; 36 37 /** 38 * Proxy for ILocationProvider implementations. 39 */ 40 public class LocationProviderProxy implements LocationProviderInterface { 41 private static final String TAG = "LocationProviderProxy"; 42 private static final boolean D = LocationManagerService.D; 43 44 private final Context mContext; 45 private final String mName; 46 private final ServiceWatcher mServiceWatcher; 47 48 private Object mLock = new Object(); 49 50 // cached values set by the location manager, synchronized on mLock 51 private ProviderProperties mProperties; 52 private boolean mEnabled = false; 53 private ProviderRequest mRequest = null; 54 private WorkSource mWorksource = new WorkSource(); 55 createAndBind( Context context, String name, String action, int overlaySwitchResId, int defaultServicePackageNameResId, int initialPackageNamesResId, Handler handler)56 public static LocationProviderProxy createAndBind( 57 Context context, String name, String action, 58 int overlaySwitchResId, int defaultServicePackageNameResId, 59 int initialPackageNamesResId, Handler handler) { 60 LocationProviderProxy proxy = new LocationProviderProxy(context, name, action, 61 overlaySwitchResId, defaultServicePackageNameResId, initialPackageNamesResId, 62 handler); 63 if (proxy.bind()) { 64 return proxy; 65 } else { 66 return null; 67 } 68 } 69 LocationProviderProxy(Context context, String name, String action, int overlaySwitchResId, int defaultServicePackageNameResId, int initialPackageNamesResId, Handler handler)70 private LocationProviderProxy(Context context, String name, String action, 71 int overlaySwitchResId, int defaultServicePackageNameResId, 72 int initialPackageNamesResId, Handler handler) { 73 mContext = context; 74 mName = name; 75 mServiceWatcher = new ServiceWatcher(mContext, TAG + "-" + name, action, overlaySwitchResId, 76 defaultServicePackageNameResId, initialPackageNamesResId, 77 mNewServiceWork, handler); 78 } 79 bind()80 private boolean bind () { 81 return mServiceWatcher.start(); 82 } 83 getService()84 private ILocationProvider getService() { 85 return ILocationProvider.Stub.asInterface(mServiceWatcher.getBinder()); 86 } 87 getConnectedPackageName()88 public String getConnectedPackageName() { 89 return mServiceWatcher.getBestPackageName(); 90 } 91 92 /** 93 * Work to apply current state to a newly connected provider. 94 * Remember we can switch the service that implements a providers 95 * at run-time, so need to apply current state. 96 */ 97 private Runnable mNewServiceWork = new Runnable() { 98 @Override 99 public void run() { 100 if (D) Log.d(TAG, "applying state to connected service"); 101 102 boolean enabled; 103 ProviderProperties properties = null; 104 ProviderRequest request; 105 WorkSource source; 106 ILocationProvider service; 107 synchronized (mLock) { 108 enabled = mEnabled; 109 request = mRequest; 110 source = mWorksource; 111 service = getService(); 112 } 113 114 if (service == null) return; 115 116 try { 117 // load properties from provider 118 properties = service.getProperties(); 119 if (properties == null) { 120 Log.e(TAG, mServiceWatcher.getBestPackageName() + 121 " has invalid locatino provider properties"); 122 } 123 124 // apply current state to new service 125 if (enabled) { 126 service.enable(); 127 if (request != null) { 128 service.setRequest(request, source); 129 } 130 } 131 } catch (RemoteException e) { 132 Log.w(TAG, e); 133 } catch (Exception e) { 134 // never let remote service crash system server 135 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 136 } 137 138 synchronized (mLock) { 139 mProperties = properties; 140 } 141 } 142 }; 143 144 @Override getName()145 public String getName() { 146 return mName; 147 } 148 149 @Override getProperties()150 public ProviderProperties getProperties() { 151 synchronized (mLock) { 152 return mProperties; 153 } 154 } 155 156 @Override enable()157 public void enable() { 158 synchronized (mLock) { 159 mEnabled = true; 160 } 161 ILocationProvider service = getService(); 162 if (service == null) return; 163 164 try { 165 service.enable(); 166 } catch (RemoteException e) { 167 Log.w(TAG, e); 168 } catch (Exception e) { 169 // never let remote service crash system server 170 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 171 } 172 } 173 174 @Override disable()175 public void disable() { 176 synchronized (mLock) { 177 mEnabled = false; 178 } 179 ILocationProvider service = getService(); 180 if (service == null) return; 181 182 try { 183 service.disable(); 184 } catch (RemoteException e) { 185 Log.w(TAG, e); 186 } catch (Exception e) { 187 // never let remote service crash system server 188 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 189 } 190 } 191 192 @Override isEnabled()193 public boolean isEnabled() { 194 synchronized (mLock) { 195 return mEnabled; 196 } 197 } 198 199 @Override setRequest(ProviderRequest request, WorkSource source)200 public void setRequest(ProviderRequest request, WorkSource source) { 201 synchronized (mLock) { 202 mRequest = request; 203 mWorksource = source; 204 } 205 ILocationProvider service = getService(); 206 if (service == null) return; 207 208 try { 209 service.setRequest(request, source); 210 } catch (RemoteException e) { 211 Log.w(TAG, e); 212 } catch (Exception e) { 213 // never let remote service crash system server 214 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 215 } 216 } 217 218 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)219 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 220 pw.append("REMOTE SERVICE"); 221 pw.append(" name=").append(mName); 222 pw.append(" pkg=").append(mServiceWatcher.getBestPackageName()); 223 pw.append(" version=").append("" + mServiceWatcher.getBestVersion()); 224 pw.append('\n'); 225 226 ILocationProvider service = getService(); 227 if (service == null) { 228 pw.println("service down (null)"); 229 return; 230 } 231 pw.flush(); 232 233 try { 234 service.asBinder().dump(fd, args); 235 } catch (RemoteException e) { 236 pw.println("service down (RemoteException)"); 237 Log.w(TAG, e); 238 } catch (Exception e) { 239 pw.println("service down (Exception)"); 240 // never let remote service crash system server 241 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 242 } 243 } 244 245 @Override getStatus(Bundle extras)246 public int getStatus(Bundle extras) { 247 ILocationProvider service = getService(); 248 if (service == null) return LocationProvider.TEMPORARILY_UNAVAILABLE; 249 250 try { 251 return service.getStatus(extras); 252 } catch (RemoteException e) { 253 Log.w(TAG, e); 254 } catch (Exception e) { 255 // never let remote service crash system server 256 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 257 } 258 return LocationProvider.TEMPORARILY_UNAVAILABLE; 259 } 260 261 @Override getStatusUpdateTime()262 public long getStatusUpdateTime() { 263 ILocationProvider service = getService(); 264 if (service == null) return 0; 265 266 try { 267 return service.getStatusUpdateTime(); 268 } catch (RemoteException e) { 269 Log.w(TAG, e); 270 } catch (Exception e) { 271 // never let remote service crash system server 272 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 273 } 274 return 0; 275 } 276 277 @Override sendExtraCommand(String command, Bundle extras)278 public boolean sendExtraCommand(String command, Bundle extras) { 279 ILocationProvider service = getService(); 280 if (service == null) return false; 281 282 try { 283 return service.sendExtraCommand(command, extras); 284 } catch (RemoteException e) { 285 Log.w(TAG, e); 286 } catch (Exception e) { 287 // never let remote service crash system server 288 Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); 289 } 290 return false; 291 } 292 } 293