1 /*
2  * Copyright (C) 2021 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 android.net;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.RequiresPermission;
22 import android.annotation.SystemApi;
23 import android.annotation.SystemService;
24 import android.content.Context;
25 import android.os.Binder;
26 import android.os.RemoteException;
27 
28 import com.android.internal.annotations.GuardedBy;
29 
30 import java.util.HashMap;
31 import java.util.Objects;
32 import java.util.concurrent.Executor;
33 
34 /**
35  * @hide
36  */
37 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
38 @SystemService(Context.PAC_PROXY_SERVICE)
39 public class PacProxyManager {
40     private final Context mContext;
41     private final IPacProxyManager mService;
42     @GuardedBy("mListenerMap")
43     private final HashMap<PacProxyInstalledListener, PacProxyInstalledListenerProxy>
44             mListenerMap = new HashMap<>();
45 
46     /** @hide */
PacProxyManager(Context context, IPacProxyManager service)47     public PacProxyManager(Context context, IPacProxyManager service) {
48         Objects.requireNonNull(service, "missing IPacProxyManager");
49         mContext = context;
50         mService = service;
51     }
52 
53     /**
54      * Add a listener to start monitoring events reported by PacProxyService.
55      */
56     @RequiresPermission(anyOf = {
57             android.Manifest.permission.NETWORK_STACK,
58             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
59             android.Manifest.permission.NETWORK_SETTINGS})
addPacProxyInstalledListener(@onNull Executor executor, @NonNull PacProxyInstalledListener listener)60     public void addPacProxyInstalledListener(@NonNull Executor executor,
61             @NonNull PacProxyInstalledListener listener) {
62         try {
63             synchronized (mListenerMap) {
64                 final PacProxyInstalledListenerProxy listenerProxy =
65                         new PacProxyInstalledListenerProxy(executor, listener);
66 
67                 if (null != mListenerMap.putIfAbsent(listener, listenerProxy)) {
68                     throw new IllegalStateException("Listener is already added.");
69                 }
70                 mService.addListener(listenerProxy);
71             }
72         } catch (RemoteException e) {
73             throw e.rethrowFromSystemServer();
74         }
75     }
76 
77     /**
78      * Remove the listener to stop monitoring the event of PacProxyInstalledListener.
79      */
80     @RequiresPermission(anyOf = {
81             android.Manifest.permission.NETWORK_STACK,
82             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
83             android.Manifest.permission.NETWORK_SETTINGS})
removePacProxyInstalledListener(@onNull PacProxyInstalledListener listener)84     public void removePacProxyInstalledListener(@NonNull PacProxyInstalledListener listener) {
85         try {
86             synchronized (mListenerMap) {
87                 final PacProxyInstalledListenerProxy listenerProxy = mListenerMap.remove(listener);
88                 if (listenerProxy == null) return;
89                 mService.removeListener(listenerProxy);
90             }
91         } catch (RemoteException e) {
92             throw e.rethrowFromSystemServer();
93         }
94     }
95 
96     /**
97      * Updates the PAC Proxy Service with current Proxy information.
98      */
99     @RequiresPermission(anyOf = {
100             android.Manifest.permission.NETWORK_STACK,
101             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
102             android.Manifest.permission.NETWORK_SETTINGS})
setCurrentProxyScriptUrl(@ullable ProxyInfo proxy)103     public void setCurrentProxyScriptUrl(@Nullable ProxyInfo proxy) {
104         try {
105             mService.setCurrentProxyScriptUrl(proxy);
106         } catch (RemoteException e) {
107             throw e.rethrowFromSystemServer();
108         }
109     }
110 
111     /**
112      * A callback interface for monitoring changes of PAC proxy information.
113      */
114     public interface PacProxyInstalledListener {
115         /**
116          * Notify that the PAC proxy has been installed. Note that this method will be called with
117          * a ProxyInfo with an empty PAC URL when the PAC proxy is removed.
118          *
119          * This method supports different PAC proxies per-network but not all devices might support
120          * per-network proxies. In that case it will be applied globally.
121          *
122          * @param network the network for which this proxy installed.
123          * @param proxy the installed proxy.
124          */
onPacProxyInstalled(@ullable Network network, @NonNull ProxyInfo proxy)125         void onPacProxyInstalled(@Nullable Network network, @NonNull ProxyInfo proxy);
126     }
127 
128     /**
129      * PacProxyInstalledListener proxy for PacProxyInstalledListener object.
130      * @hide
131      */
132     public class PacProxyInstalledListenerProxy extends IPacProxyInstalledListener.Stub {
133         private final Executor mExecutor;
134         private final PacProxyInstalledListener mListener;
135 
PacProxyInstalledListenerProxy(Executor executor, PacProxyInstalledListener listener)136         PacProxyInstalledListenerProxy(Executor executor, PacProxyInstalledListener listener) {
137             mExecutor = executor;
138             mListener = listener;
139         }
140 
141         @Override
onPacProxyInstalled(Network network, ProxyInfo proxy)142         public void onPacProxyInstalled(Network network, ProxyInfo proxy) {
143             Binder.withCleanCallingIdentity(() -> {
144                 mExecutor.execute(() -> {
145                     mListener.onPacProxyInstalled(network, proxy);
146                 });
147             });
148         }
149     }
150 }
151