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