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.setComponent(mServiceInfo.getComponentName()); 82 mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, 83 UserHandle.CURRENT_OR_SELF); 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