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 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 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 80 private boolean bind () { 81 return mServiceWatcher.start(); 82 } 83 84 private ILocationProvider getService() { 85 return ILocationProvider.Stub.asInterface(mServiceWatcher.getBinder()); 86 } 87 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 145 public String getName() { 146 return mName; 147 } 148 149 @Override 150 public ProviderProperties getProperties() { 151 synchronized (mLock) { 152 return mProperties; 153 } 154 } 155 156 @Override 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 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 193 public boolean isEnabled() { 194 synchronized (mLock) { 195 return mEnabled; 196 } 197 } 198 199 @Override 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 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 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 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 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