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