Home | History | Annotate | Download | only in location
      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