1 /*
2  * Copyright (C) 2019 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.tv.settings.users;
18 
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.ServiceConnection;
23 import android.os.IBinder;
24 import android.os.RemoteException;
25 import android.os.UserHandle;
26 import android.util.Log;
27 
28 import java.util.concurrent.TimeUnit;
29 import java.util.concurrent.atomic.AtomicReference;
30 
31 class RestrictedProfilePinServiceConnection implements ServiceConnection {
32     private static final String TAG = RestrictedProfilePinServiceConnection.class.getSimpleName();
33     public static final long CONNECTION_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5);
34 
35     private Context mContext;
36 
37     private final AtomicReference<IRestrictedProfilePinService> mPinServiceRef =
38             new AtomicReference<>();
39 
RestrictedProfilePinServiceConnection(Context context)40     RestrictedProfilePinServiceConnection(Context context) {
41         mContext = context;
42     }
43 
44     @Override
onServiceConnected(ComponentName name, IBinder binder)45     public void onServiceConnected(ComponentName name, IBinder binder) {
46         synchronized (mPinServiceRef) {
47             mPinServiceRef.set(IRestrictedProfilePinService.Stub.asInterface(binder));
48             mPinServiceRef.notifyAll();
49         }
50         Log.d(TAG, "RestrictedProfilePinService connected");
51     }
52 
53     @Override
onServiceDisconnected(ComponentName name)54     public void onServiceDisconnected(ComponentName name) {
55         synchronized (mPinServiceRef) {
56             mPinServiceRef.set(null);
57         }
58         Log.e(TAG, "RestrictedProfilePinService disconnected");
59     }
60 
61     @Override
onNullBinding(ComponentName name)62     public void onNullBinding(ComponentName name) {
63         mPinServiceRef.set(null);
64         Log.w(TAG, "Could not bind to RestrictedProfilePinService");
65     }
66 
67     @Override
onBindingDied(ComponentName name)68     public void onBindingDied(ComponentName name) {
69         mPinServiceRef.set(null);
70         Log.e(TAG, "Connection to RestrictedProfilePinService died");
71     }
72 
getPinService()73     IRestrictedProfilePinService getPinService() throws RemoteException {
74         synchronized (mPinServiceRef) {
75             if (!waitForService()) {
76                 throw new RemoteException("Connecting to RestrictedProfilePinService failed.");
77             }
78 
79             return mPinServiceRef.get();
80         }
81     }
82 
bindPinService()83     void bindPinService() {
84         if (mPinServiceRef.get() == null) {
85             Intent intent = new Intent(mContext, RestrictedProfilePinService.class);
86             mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
87         }
88     }
89 
unbindPinService()90     void unbindPinService() {
91         mContext.unbindService(this);
92     }
93 
waitForService()94     private boolean waitForService() {
95         try {
96             synchronized (mPinServiceRef) {
97                 if (mPinServiceRef.get() == null) {
98                     Log.w(TAG, "No connection to pin service. Waiting for connection...");
99                     mPinServiceRef.wait(CONNECTION_TIMEOUT_MILLIS);
100                 }
101             }
102         } catch (InterruptedException e) {
103             e.printStackTrace();
104         }
105 
106         return mPinServiceRef.get() != null;
107     }
108 }
109