1 /*
2  * Copyright (C) 2015 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 package com.android.car.pm;
17 
18 import android.car.content.pm.CarAppBlockingPolicy;
19 import android.car.content.pm.ICarAppBlockingPolicy;
20 import android.car.content.pm.ICarAppBlockingPolicySetter;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.ServiceConnection;
25 import android.content.pm.ServiceInfo;
26 import android.os.Handler;
27 import android.os.IBinder;
28 import android.os.RemoteException;
29 import android.os.UserHandle;
30 import android.util.Slog;
31 
32 import com.android.car.CarLog;
33 import com.android.internal.annotations.GuardedBy;
34 
35 public class AppBlockingPolicyProxy implements ServiceConnection {
36 
37     private static final String TAG = CarLog.tagFor(AppBlockingPolicyProxy.class);
38 
39     private final CarPackageManagerService mService;
40     private final Context mContext;
41     private final ServiceInfo mServiceInfo;
42     private final ICarAppBlockingPolicySetterImpl mSetter;
43     private final Object mLock = new Object();
44 
45     @GuardedBy("mLock")
46     private ICarAppBlockingPolicy mPolicyService;
47 
48     /**
49      * policy not set within this time after binding will be treated as failure and will be
50      * ignored.
51      */
52     private static final long TIMEOUT_MS = 5000;
53     private static final int MAX_CRASH_RETRY = 2;
54     @GuardedBy("mLock")
55     private int mCrashCount;
56     @GuardedBy("mLock")
57     private boolean mBound;
58 
59     private final Handler mHandler;
60     private final Runnable mTimeoutRunnable = new Runnable() {
61         @Override
62         public void run() {
63             Slog.w(TAG, "Timeout for policy setting for service:" + mServiceInfo);
64             disconnect();
65             mService.onPolicyConnectionFailure(AppBlockingPolicyProxy.this);
66         }
67     };
68 
AppBlockingPolicyProxy(CarPackageManagerService service, Context context, ServiceInfo serviceInfo)69     public AppBlockingPolicyProxy(CarPackageManagerService service, Context context,
70             ServiceInfo serviceInfo) {
71         mService = service;
72         mContext = context;
73         mServiceInfo = serviceInfo;
74         mSetter = new ICarAppBlockingPolicySetterImpl();
75         mHandler = new Handler(mService.getLooper());
76     }
77 
getPackageName()78     public String getPackageName() {
79         return mServiceInfo.packageName;
80     }
81 
connect()82     public void connect() {
83         Intent intent = new Intent();
84         intent.setComponent(mServiceInfo.getComponentName());
85         mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
86                 UserHandle.CURRENT_OR_SELF);
87         synchronized (mLock) {
88             mBound = true;
89         }
90         mHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MS);
91     }
92 
disconnect()93     public void disconnect() {
94         synchronized (mLock) {
95             if (!mBound) {
96                 return;
97             }
98             mBound = false;
99             mPolicyService = null;
100         }
101         mHandler.removeCallbacks(mTimeoutRunnable);
102         try {
103             mContext.unbindService(this);
104         } catch (IllegalArgumentException e) {
105             Slog.w(TAG, "unbind", e);
106         }
107     }
108 
109     @Override
onServiceConnected(ComponentName name, IBinder service)110     public void onServiceConnected(ComponentName name, IBinder service) {
111         ICarAppBlockingPolicy policy = null;
112         boolean failed = false;
113         synchronized (mLock) {
114             mPolicyService = ICarAppBlockingPolicy.Stub.asInterface(service);
115             policy = mPolicyService;
116             if (policy == null) {
117                 failed = true;
118             }
119         }
120         if (failed) {
121             Slog.w(TAG, "Policy service connected with null binder:" + name);
122             mService.onPolicyConnectionFailure(this);
123             return;
124         }
125         try {
126             policy.setAppBlockingPolicySetter(mSetter);
127         } catch (RemoteException e) {
128             // let retry handle this
129         }
130     }
131 
132     @Override
onServiceDisconnected(ComponentName name)133     public void onServiceDisconnected(ComponentName name) {
134         boolean failed = false;
135         synchronized (mLock) {
136             mCrashCount++;
137             if (mCrashCount > MAX_CRASH_RETRY) {
138                 mPolicyService = null;
139                 failed = true;
140             }
141         }
142         if (failed) {
143             Slog.w(TAG, "Policy service keep crashing, giving up:" + name);
144             mService.onPolicyConnectionFailure(this);
145         }
146     }
147 
148     @Override
toString()149     public String toString() {
150         return "AppBlockingPolicyProxy [mServiceInfo=" + mServiceInfo + ", mCrashCount="
151                 + mCrashCount + "]";
152     }
153 
154     private class ICarAppBlockingPolicySetterImpl extends ICarAppBlockingPolicySetter.Stub {
155 
156         @Override
setAppBlockingPolicy(CarAppBlockingPolicy policy)157         public void setAppBlockingPolicy(CarAppBlockingPolicy policy) {
158             mHandler.removeCallbacks(mTimeoutRunnable);
159             if (policy == null) {
160                 Slog.w(TAG, "setAppBlockingPolicy null policy from policy service:" + mServiceInfo);
161             }
162             mService.onPolicyConnectionAndSet(AppBlockingPolicyProxy.this, policy);
163         }
164     }
165 }
166