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