1 /*
2  * Copyright (C) 2020 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.cts.deviceowner.proxy;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.net.ProxyInfo;
24 import android.net.Uri;
25 import android.text.TextUtils;
26 import android.util.Log;
27 
28 import com.android.cts.deviceowner.BaseDeviceOwnerTest;
29 
30 import java.net.Proxy;
31 import java.util.ArrayList;
32 import java.util.List;
33 import java.util.concurrent.Semaphore;
34 import java.util.concurrent.TimeUnit;
35 
36 public class BaseProxyTest extends BaseDeviceOwnerTest {
37   static final String TAG = "ProxyCtsTest";
38   protected static final int TIME_OUT_SECS = 10;
39 
40   protected ProxyInfo mProxy;
41   protected String mProxyHost = "localhost";
42 
43   private ProxyBroadcastReceiver mReceiver;
44 
45   @Override
setUp()46   protected void setUp() throws Exception {
47     super.setUp();
48     // Register a broadcast receiver and wait for the first sticky broadcast to come in.
49     registerAndWaitForStickyBroadcast();
50 
51     if (isProxyStatic() || isProxyPac()) {
52       // If there is a proxy set, try to clear it so we can test properly.
53       // If we can't clear it then we can't run the test.
54       assertTrue("No broadcast after clearing proxy.", clearProxyAndWaitForBroadcast());
55       waitForClearProxySysProp();
56     }
57   }
58 
registerAndWaitForStickyBroadcast()59   private void registerAndWaitForStickyBroadcast() throws Exception {
60     mReceiver = new ProxyBroadcastReceiver();
61     mContext.registerReceiver(mReceiver,
62         new IntentFilter(android.net.Proxy.PROXY_CHANGE_ACTION));
63     // don't assert the outcome, as there might not be a sticky broadcast yet, when this is run
64     // for the first time after a reboot
65     mReceiver.waitForBroadcast();
66   }
67 
68   @Override
tearDown()69   protected void tearDown() throws Exception {
70     Log.d(TAG, "tearDown");
71     // Do not assert the outcome, as there will be no broadcast if clear proxy is performed while
72     // the system has no proxy configured.
73     clearProxyAndWaitForBroadcast();
74     waitForClearProxySysProp();
75     mContext.unregisterReceiver(mReceiver);
76     super.tearDown();
77   }
78 
79   /**
80    * Set the global proxy.
81    */
setProxyAndWaitForBroadcast(ProxyInfo proxy)82   protected boolean setProxyAndWaitForBroadcast(ProxyInfo proxy) throws Exception {
83     Log.d(TAG, "setProxyAndWaitForBroadcast(), setting Proxy to " + proxy);
84     mDevicePolicyManager.setRecommendedGlobalProxy(getWho(), proxy);
85     return mReceiver.waitForBroadcast();
86   }
87 
88   /**
89    * Clear the global proxy.
90    */
clearProxyAndWaitForBroadcast()91   protected boolean clearProxyAndWaitForBroadcast() throws Exception {
92     return setProxyAndWaitForBroadcast(null);
93   }
94 
isProxyEmpty()95   protected boolean isProxyEmpty() {
96     return (mProxy == null) || (TextUtils.isEmpty(mProxy.getHost())
97         && (mProxy.getPacFileUrl() == Uri.EMPTY));
98   }
99 
isProxyStatic()100   protected boolean isProxyStatic() {
101     return (mProxy != null) && !TextUtils.isEmpty(mProxy.getHost());
102   }
103 
isProxyPac()104   private boolean isProxyPac() {
105     return (mProxy != null) && (mProxy.getPacFileUrl() != Uri.EMPTY);
106   }
107 
isCorrectPacProxy(Uri pacUri)108   protected boolean isCorrectPacProxy(Uri pacUri) {
109     return isProxyPac() && pacUri.equals(mProxy.getPacFileUrl());
110   }
111 
112   /**
113    * Check if the java proxy property is set correctly.
114    */
isProxySysPropSet()115   private boolean isProxySysPropSet() {
116     String proxy = System.getProperty("http.proxyHost");
117     return (proxy != null) && proxy.equals(mProxyHost);
118   }
119 
120   // Since this is a java system property there is no good way to wait for
121   // this other than to poll for it to be the correct value.
waitForSetProxySysProp()122   protected void waitForSetProxySysProp() {
123     int ct = 0;
124     while (!isProxySysPropSet() && (++ct < (TIME_OUT_SECS * 10))) {
125       try {
126         Thread.sleep(100);
127       } catch (InterruptedException e) {
128       }
129     }
130     assertTrue("Timed out waiting for proxy to set", isProxySysPropSet());
131   }
132 
133   /**
134    * Check if the java proxy property is clear.
135    */
isProxySysPropClear()136   private boolean isProxySysPropClear() {
137     return TextUtils.isEmpty(System.getProperty("http.proxyHost"));
138   }
139 
140   // Since this is a java system property there is no good way to wait for
141   // this other than to poll for it to be the correct value.
waitForClearProxySysProp()142   protected void waitForClearProxySysProp() {
143     int ct = 0;
144     while (!isProxySysPropClear() && (++ct < (TIME_OUT_SECS * 10))) {
145       try {
146         Thread.sleep(100);
147       } catch (InterruptedException e) {
148       }
149     }
150     assertTrue("Timed out waiting for proxy to clear", isProxySysPropClear());
151   }
152 
153   // Utility function.
newArrayList(Proxy... proxies)154   protected List<Proxy> newArrayList(Proxy... proxies) {
155     List<Proxy> ret = new ArrayList<Proxy>();
156     for (Proxy p : proxies) {
157       ret.add(p);
158     }
159     return ret;
160   }
161 
162   private class ProxyBroadcastReceiver extends BroadcastReceiver {
163     private final Semaphore mSemaphore = new Semaphore(0);
164 
165     @Override
onReceive(Context context, Intent intent)166     public void onReceive(Context context, Intent intent) {
167       mProxy = intent.getParcelableExtra(android.net.Proxy.EXTRA_PROXY_INFO);
168       Log.d(TAG, "Proxy received " + mProxy);
169       mSemaphore.release();
170     }
171 
waitForBroadcast()172     public boolean waitForBroadcast() throws Exception {
173       if (mSemaphore.tryAcquire(10, TimeUnit.SECONDS)) {
174         return true;
175       }
176       return false;
177     }
178   }
179 }
180