diff options
author | Aaron Huang <huangaaron@google.com> | 2021-03-15 12:56:09 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-03-15 12:56:09 +0000 |
commit | e29f0a55d87dd8d102f04322cb43cdd020c37b61 (patch) | |
tree | 94b2176db4ca340cf6006f7a8579be3dbf94a93f | |
parent | dbbc6224dae045146316c2aadd333f1f92d58856 (diff) | |
parent | ce43593e5ee5d82148b184310c92af60d05007dc (diff) |
Merge changes from topic "pacproxy-service" am: 16f50075b1 am: 688ae36dcb am: ce43593e5e
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1553959
MUST ONLY BE SUBMITTED BY AUTOMERGER
Change-Id: If6d34753e8bf9201e16121b8f3c6c83aa6358986
14 files changed, 374 insertions, 64 deletions
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 18b0a4344414..64f56bf315af 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -203,6 +203,16 @@ package android.net { method @Nullable public byte[] getWatchlistConfigHash(); } + public class PacProxyManager { + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void addPacProxyInstalledListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.PacProxyManager.PacProxyInstalledListener); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void removePacProxyInstalledListener(@NonNull android.net.PacProxyManager.PacProxyInstalledListener); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setCurrentProxyScriptUrl(@Nullable android.net.ProxyInfo); + } + + public static interface PacProxyManager.PacProxyInstalledListener { + method public void onPacProxyInstalled(@Nullable android.net.Network, @NonNull android.net.ProxyInfo); + } + public final class Proxy { method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo); } diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 43c14a99b221..31b0d413c395 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -129,11 +129,13 @@ import android.net.EthernetManager; import android.net.IEthernetManager; import android.net.IIpSecService; import android.net.INetworkPolicyManager; +import android.net.IPacProxyManager; import android.net.IVpnManager; import android.net.IpSecManager; import android.net.NetworkPolicyManager; import android.net.NetworkScoreManager; import android.net.NetworkWatchlistManager; +import android.net.PacProxyManager; import android.net.TetheringManager; import android.net.VpnManager; import android.net.lowpan.ILowpanManager; @@ -374,6 +376,15 @@ public final class SystemServiceRegistry { // (which extends it). SYSTEM_SERVICE_NAMES.put(android.text.ClipboardManager.class, Context.CLIPBOARD_SERVICE); + registerService(Context.PAC_PROXY_SERVICE, PacProxyManager.class, + new CachedServiceFetcher<PacProxyManager>() { + @Override + public PacProxyManager createService(ContextImpl ctx) throws ServiceNotFoundException { + IBinder b = ServiceManager.getServiceOrThrow(Context.PAC_PROXY_SERVICE); + IPacProxyManager service = IPacProxyManager.Stub.asInterface(b); + return new PacProxyManager(ctx.getOuterContext(), service); + }}); + registerService(Context.NETD_SERVICE, IBinder.class, new StaticServiceFetcher<IBinder>() { @Override public IBinder createService() throws ServiceNotFoundException { diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 25234592f4c4..f8dd0e1452e5 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3531,6 +3531,7 @@ public abstract class Context { VIBRATOR_SERVICE, //@hide: STATUS_BAR_SERVICE, CONNECTIVITY_SERVICE, + PAC_PROXY_SERVICE, VCN_MANAGEMENT_SERVICE, //@hide: IP_MEMORY_STORE_SERVICE, IPSEC_SERVICE, @@ -4137,6 +4138,17 @@ public abstract class Context { public static final String CONNECTIVITY_SERVICE = "connectivity"; /** + * Use with {@link #getSystemService(String)} to retrieve a {@link + * android.net.PacProxyManager} for handling management of + * pac proxy information. + * + * @see #getSystemService(String) + * @see android.net.PacProxyManager + * @hide + */ + public static final String PAC_PROXY_SERVICE = "pac_proxy"; + + /** * Use with {@link #getSystemService(String)} to retrieve a {@link android.net.vcn.VcnManager} * for managing Virtual Carrier Networks * diff --git a/core/java/android/net/IPacProxyInstalledListener.aidl b/core/java/android/net/IPacProxyInstalledListener.aidl new file mode 100644 index 000000000000..b1f946e02215 --- /dev/null +++ b/core/java/android/net/IPacProxyInstalledListener.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.net.Network; +import android.net.ProxyInfo; + +/** {@hide} */ +oneway interface IPacProxyInstalledListener { + void onPacProxyInstalled(in Network network, in ProxyInfo proxy); +} diff --git a/core/java/android/net/IPacProxyManager.aidl b/core/java/android/net/IPacProxyManager.aidl new file mode 100644 index 000000000000..8f65c56662ef --- /dev/null +++ b/core/java/android/net/IPacProxyManager.aidl @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2021, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing perNmissions and + * limitations under the License. + */ + +package android.net; + +import android.net.IPacProxyInstalledListener; +import android.net.ProxyInfo; + +/** {@hide} */ +interface IPacProxyManager +{ + void addListener(IPacProxyInstalledListener listener); + void removeListener(IPacProxyInstalledListener listener); + void setCurrentProxyScriptUrl(in ProxyInfo proxyInfo); +} diff --git a/core/java/android/net/PacProxyManager.java b/core/java/android/net/PacProxyManager.java new file mode 100644 index 000000000000..8f7ad8c335ca --- /dev/null +++ b/core/java/android/net/PacProxyManager.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.annotation.SystemService; +import android.content.Context; +import android.os.Binder; +import android.os.RemoteException; + +import com.android.internal.annotations.GuardedBy; + +import java.util.HashMap; +import java.util.Objects; +import java.util.concurrent.Executor; + +/** + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +@SystemService(Context.PAC_PROXY_SERVICE) +public class PacProxyManager { + private final Context mContext; + private final IPacProxyManager mService; + @GuardedBy("mListenerMap") + private final HashMap<PacProxyInstalledListener, PacProxyInstalledListenerProxy> + mListenerMap = new HashMap<>(); + + /** @hide */ + public PacProxyManager(Context context, IPacProxyManager service) { + Objects.requireNonNull(service, "missing IPacProxyManager"); + mContext = context; + mService = service; + } + + /** + * Add a listener to start monitoring events reported by PacProxyService. + */ + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STACK, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_SETTINGS}) + public void addPacProxyInstalledListener(@NonNull Executor executor, + @NonNull PacProxyInstalledListener listener) { + try { + synchronized (mListenerMap) { + final PacProxyInstalledListenerProxy listenerProxy = + new PacProxyInstalledListenerProxy(executor, listener); + + if (null != mListenerMap.putIfAbsent(listener, listenerProxy)) { + throw new IllegalStateException("Listener is already added."); + } + mService.addListener(listenerProxy); + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Remove the listener to stop monitoring the event of PacProxyInstalledListener. + */ + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STACK, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_SETTINGS}) + public void removePacProxyInstalledListener(@NonNull PacProxyInstalledListener listener) { + try { + synchronized (mListenerMap) { + final PacProxyInstalledListenerProxy listenerProxy = mListenerMap.remove(listener); + if (listenerProxy == null) return; + mService.removeListener(listenerProxy); + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Updates the PAC Proxy Installer with current Proxy information. + */ + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STACK, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_SETTINGS}) + public void setCurrentProxyScriptUrl(@Nullable ProxyInfo proxy) { + try { + mService.setCurrentProxyScriptUrl(proxy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * A callback interface for monitoring changes of PAC proxy information. + */ + public interface PacProxyInstalledListener { + /** + * Notify that the PAC proxy has been installed. Note that this method will be called with + * a ProxyInfo with an empty PAC URL when the PAC proxy is removed. + * + * This method supports different PAC proxies per-network but not all devices might support + * per-network proxies. In that case it will be applied globally. + * + * @param network the network for which this proxy installed. + * @param proxy the installed proxy. + */ + void onPacProxyInstalled(@Nullable Network network, @NonNull ProxyInfo proxy); + } + + /** + * PacProxyInstalledListener proxy for PacProxyInstalledListener object. + * @hide + */ + public class PacProxyInstalledListenerProxy extends IPacProxyInstalledListener.Stub { + private final Executor mExecutor; + private final PacProxyInstalledListener mListener; + + PacProxyInstalledListenerProxy(Executor executor, PacProxyInstalledListener listener) { + mExecutor = executor; + mListener = listener; + } + + @Override + public void onPacProxyInstalled(Network network, ProxyInfo proxy) { + Binder.withCleanCallingIdentity(() -> { + mExecutor.execute(() -> { + mListener.onPacProxyInstalled(network, proxy); + }); + }); + } + } +} diff --git a/core/java/android/net/PacProxySelector.java b/core/java/android/net/PacProxySelector.java index 326943a27d4e..84b7eecd2027 100644 --- a/core/java/android/net/PacProxySelector.java +++ b/core/java/android/net/PacProxySelector.java @@ -51,7 +51,7 @@ public class PacProxySelector extends ProxySelector { ServiceManager.getService(PROXY_SERVICE)); if (mProxyService == null) { // Added because of b10267814 where mako is restarting. - Log.e(TAG, "PacProxyInstaller: no proxy service"); + Log.e(TAG, "PacProxyService: no proxy service"); } mDefaultList = Lists.newArrayList(java.net.Proxy.NO_PROXY); } diff --git a/packages/Connectivity/framework/src/android/net/ProxyInfo.java b/packages/Connectivity/framework/src/android/net/ProxyInfo.java index 229db0d717cd..745e20f1542e 100644 --- a/packages/Connectivity/framework/src/android/net/ProxyInfo.java +++ b/packages/Connectivity/framework/src/android/net/ProxyInfo.java @@ -129,7 +129,7 @@ public class ProxyInfo implements Parcelable { } /** - * Only used in PacProxyInstaller after Local Proxy is bound. + * Only used in PacProxyService after Local Proxy is bound. * @hide */ public ProxyInfo(@NonNull Uri pacFileUrl, int localProxyPort) { diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java index f8b9309f9a7f..f0de81183919 100644 --- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java +++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java @@ -360,7 +360,7 @@ public class ProxyServer extends Thread { try { mCallback.setProxyPort(port); } catch (RemoteException e) { - Log.w(TAG, "Proxy failed to report port to PacProxyInstaller", e); + Log.w(TAG, "Proxy failed to report port to PacProxyService", e); } } mPort = port; @@ -371,7 +371,7 @@ public class ProxyServer extends Thread { try { callback.setProxyPort(mPort); } catch (RemoteException e) { - Log.w(TAG, "Proxy failed to report port to PacProxyInstaller", e); + Log.w(TAG, "Proxy failed to report port to PacProxyService", e); } } mCallback = callback; diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java index bdf478d36c8c..a8e26221a7ab 100644 --- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java +++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java @@ -30,7 +30,7 @@ public class ProxyService extends Service { private static ProxyServer server = null; - /** Keep these values up-to-date with PacProxyInstaller.java */ + /** Keep these values up-to-date with PacProxyService.java */ public static final String KEY_PROXY = "keyProxy"; public static final String HOST = "localhost"; public static final String EXCL_LIST = ""; diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index b4fcaeedd845..688b33e0f685 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -4425,7 +4425,8 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } case EVENT_PROXY_HAS_CHANGED: { - handleApplyDefaultProxy((ProxyInfo)msg.obj); + final Pair<Network, ProxyInfo> arg = (Pair<Network, ProxyInfo>) msg.obj; + handleApplyDefaultProxy(arg.second); break; } case EVENT_REGISTER_NETWORK_PROVIDER: { diff --git a/services/core/java/com/android/server/connectivity/PacProxyInstaller.java b/services/core/java/com/android/server/connectivity/PacProxyService.java index aadaf4d9584f..d23b488f3054 100644 --- a/services/core/java/com/android/server/connectivity/PacProxyInstaller.java +++ b/services/core/java/com/android/server/connectivity/PacProxyService.java @@ -16,6 +16,8 @@ package com.android.server.connectivity; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.WorkerThread; import android.app.AlarmManager; import android.app.PendingIntent; @@ -26,12 +28,16 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; +import android.net.IPacProxyInstalledListener; +import android.net.IPacProxyManager; import android.net.ProxyInfo; import android.net.TrafficStats; import android.net.Uri; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IBinder; +import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -44,6 +50,7 @@ import com.android.internal.util.TrafficStatsConstants; import com.android.net.IProxyCallback; import com.android.net.IProxyPortListener; import com.android.net.IProxyService; +import com.android.net.module.util.PermissionUtils; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -53,7 +60,7 @@ import java.net.URLConnection; /** * @hide */ -public class PacProxyInstaller { +public class PacProxyService extends IPacProxyManager.Stub { private static final String PAC_PACKAGE = "com.android.pacprocessor"; private static final String PAC_SERVICE = "com.android.pacprocessor.PacService"; private static final String PAC_SERVICE_NAME = "com.android.net.IProxyService"; @@ -61,7 +68,7 @@ public class PacProxyInstaller { private static final String PROXY_PACKAGE = "com.android.proxyhandler"; private static final String PROXY_SERVICE = "com.android.proxyhandler.ProxyService"; - private static final String TAG = "PacProxyInstaller"; + private static final String TAG = "PacProxyService"; private static final String ACTION_PAC_REFRESH = "android.net.proxy.PAC_REFRESH"; @@ -71,10 +78,6 @@ public class PacProxyInstaller { private static final int DELAY_LONG = 4; private static final long MAX_PAC_SIZE = 20 * 1000 * 1000; - // Return values for #setCurrentProxyScriptUrl - public static final boolean DONT_SEND_BROADCAST = false; - public static final boolean DO_SEND_BROADCAST = true; - private String mCurrentPac; @GuardedBy("mProxyLock") private volatile Uri mPacUrl = Uri.EMPTY; @@ -93,8 +96,8 @@ public class PacProxyInstaller { private volatile boolean mHasSentBroadcast; private volatile boolean mHasDownloaded; - private Handler mConnectivityHandler; - private final int mProxyMessage; + private final RemoteCallbackList<IPacProxyInstalledListener> + mCallbacks = new RemoteCallbackList<>(); /** * Used for locking when setting mProxyService and all references to mCurrentPac. @@ -102,6 +105,13 @@ public class PacProxyInstaller { private final Object mProxyLock = new Object(); /** + * Lock ensuring consistency between the values of mHasSentBroadcast, mHasDownloaded, the + * last URL and port, and the broadcast message being sent with the correct arguments. + * TODO : this should probably protect all instances of these variables + */ + private final Object mBroadcastStateLock = new Object(); + + /** * Runnable to download PAC script. * The behavior relies on the assumption it always runs on mNetThread to guarantee that the * latest data fetched from mPacUrl is stored in mProxyService. @@ -146,10 +156,10 @@ public class PacProxyInstaller { } } - public PacProxyInstaller(Context context, Handler handler, int proxyMessage) { + public PacProxyService(@NonNull Context context) { mContext = context; mLastPort = -1; - final HandlerThread netThread = new HandlerThread("android.pacproxyinstaller", + final HandlerThread netThread = new HandlerThread("android.pacproxyservice", android.os.Process.THREAD_PRIORITY_DEFAULT); netThread.start(); mNetThreadHandler = new Handler(netThread.getLooper()); @@ -158,8 +168,6 @@ public class PacProxyInstaller { context, 0, new Intent(ACTION_PAC_REFRESH), PendingIntent.FLAG_IMMUTABLE); context.registerReceiver(new PacRefreshIntentReceiver(), new IntentFilter(ACTION_PAC_REFRESH)); - mConnectivityHandler = handler; - mProxyMessage = proxyMessage; } private AlarmManager getAlarmManager() { @@ -169,38 +177,52 @@ public class PacProxyInstaller { return mAlarmManager; } + @Override + public void addListener(IPacProxyInstalledListener listener) { + PermissionUtils.enforceNetworkStackPermissionOr(mContext, + android.Manifest.permission.NETWORK_SETTINGS); + mCallbacks.register(listener); + } + + @Override + public void removeListener(IPacProxyInstalledListener listener) { + PermissionUtils.enforceNetworkStackPermissionOr(mContext, + android.Manifest.permission.NETWORK_SETTINGS); + mCallbacks.unregister(listener); + } + /** * Updates the PAC Proxy Installer with current Proxy information. This is called by - * the ProxyTracker directly before a broadcast takes place to allow - * the PacProxyInstaller to indicate that the broadcast should not be sent and the - * PacProxyInstaller will trigger a new broadcast when it is ready. + * the ProxyTracker through PacProxyManager before a broadcast takes place to allow + * the PacProxyService to indicate that the broadcast should not be sent and the + * PacProxyService will trigger a new broadcast when it is ready. * * @param proxy Proxy information that is about to be broadcast. - * @return Returns whether the broadcast should be sent : either DO_ or DONT_SEND_BROADCAST */ - public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) { - if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) { - if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) { - // Allow to send broadcast, nothing to do. - return DO_SEND_BROADCAST; - } - mPacUrl = proxy.getPacFileUrl(); - mCurrentDelay = DELAY_1; - mHasSentBroadcast = false; - mHasDownloaded = false; - getAlarmManager().cancel(mPacRefreshIntent); - bind(); - return DONT_SEND_BROADCAST; - } else { - getAlarmManager().cancel(mPacRefreshIntent); - synchronized (mProxyLock) { - mPacUrl = Uri.EMPTY; - mCurrentPac = null; - if (mProxyService != null) { - unbind(); + @Override + public void setCurrentProxyScriptUrl(@Nullable ProxyInfo proxy) { + PermissionUtils.enforceNetworkStackPermissionOr(mContext, + android.Manifest.permission.NETWORK_SETTINGS); + + synchronized (mBroadcastStateLock) { + if (proxy != null && !Uri.EMPTY.equals(proxy.getPacFileUrl())) { + if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) return; + mPacUrl = proxy.getPacFileUrl(); + mCurrentDelay = DELAY_1; + mHasSentBroadcast = false; + mHasDownloaded = false; + getAlarmManager().cancel(mPacRefreshIntent); + bind(); + } else { + getAlarmManager().cancel(mPacRefreshIntent); + synchronized (mProxyLock) { + mPacUrl = Uri.EMPTY; + mCurrentPac = null; + if (mProxyService != null) { + unbind(); + } } } - return DO_SEND_BROADCAST; } } @@ -275,6 +297,7 @@ public class PacProxyInstaller { getAlarmManager().set(AlarmManager.ELAPSED_REALTIME, timeTillTrigger, mPacRefreshIntent); } + @GuardedBy("mProxyLock") private void setCurrentProxyScript(String script) { if (mProxyService == null) { Log.e(TAG, "setCurrentProxyScript: no proxy service"); @@ -347,6 +370,9 @@ public class PacProxyInstaller { public void setProxyPort(int port) { if (mLastPort != -1) { // Always need to send if port changed + // TODO: Here lacks synchronization because this write cannot + // guarantee that it's visible from sendProxyIfNeeded() when + // it's called by a Runnable which is post by mNetThread. mHasSentBroadcast = false; } mLastPort = port; @@ -365,8 +391,9 @@ public class PacProxyInstaller { } } }; - mContext.bindService(intent, mProxyConnection, - Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE); + mContext.bindService(intent, + Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE, + new HandlerExecutor(mNetThreadHandler), mProxyConnection); } private void unbind() { @@ -383,16 +410,28 @@ public class PacProxyInstaller { } private void sendPacBroadcast(ProxyInfo proxy) { - mConnectivityHandler.sendMessage(mConnectivityHandler.obtainMessage(mProxyMessage, proxy)); + final int length = mCallbacks.beginBroadcast(); + for (int i = 0; i < length; i++) { + final IPacProxyInstalledListener listener = mCallbacks.getBroadcastItem(i); + if (listener != null) { + try { + listener.onPacProxyInstalled(null /* network */, proxy); + } catch (RemoteException ignored) { } + } + } + mCallbacks.finishBroadcast(); } - private synchronized void sendProxyIfNeeded() { - if (!mHasDownloaded || (mLastPort == -1)) { - return; - } - if (!mHasSentBroadcast) { - sendPacBroadcast(ProxyInfo.buildPacProxy(mPacUrl, mLastPort)); - mHasSentBroadcast = true; + // This method must be called on mNetThreadHandler. + private void sendProxyIfNeeded() { + synchronized (mBroadcastStateLock) { + if (!mHasDownloaded || (mLastPort == -1)) { + return; + } + if (!mHasSentBroadcast) { + sendPacBroadcast(ProxyInfo.buildPacProxy(mPacUrl, mLastPort)); + mHasSentBroadcast = true; + } } } } diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java index d83ff837d9be..8b9c83678777 100644 --- a/services/core/java/com/android/server/connectivity/ProxyTracker.java +++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java @@ -27,15 +27,19 @@ import android.annotation.Nullable; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.net.Network; +import android.net.PacProxyManager; import android.net.Proxy; import android.net.ProxyInfo; import android.net.Uri; import android.os.Binder; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; +import android.util.Pair; import com.android.internal.annotations.GuardedBy; import com.android.net.module.util.ProxyUtils; @@ -67,7 +71,7 @@ public class ProxyTracker { // is not set. Individual networks have their own settings that override this. This member // is set through setDefaultProxy, which is called when the default network changes proxies // in its LinkProperties, or when ConnectivityService switches to a new default network, or - // when PacProxyInstaller resolves the proxy. + // when PacProxyService resolves the proxy. @Nullable @GuardedBy("mProxyLock") private volatile ProxyInfo mDefaultProxy = null; @@ -77,16 +81,31 @@ public class ProxyTracker { private final Handler mConnectivityServiceHandler; - // The object responsible for Proxy Auto Configuration (PAC). - @NonNull - private final PacProxyInstaller mPacProxyInstaller; + private final PacProxyManager mPacProxyManager; + + private class PacProxyInstalledListener implements PacProxyManager.PacProxyInstalledListener { + private final int mEvent; + + PacProxyInstalledListener(int event) { + mEvent = event; + } + + public void onPacProxyInstalled(@Nullable Network network, @NonNull ProxyInfo proxy) { + mConnectivityServiceHandler + .sendMessage(mConnectivityServiceHandler + .obtainMessage(mEvent, new Pair<>(network, proxy))); + } + } public ProxyTracker(@NonNull final Context context, @NonNull final Handler connectivityServiceInternalHandler, final int pacChangedEvent) { mContext = context; mConnectivityServiceHandler = connectivityServiceInternalHandler; - mPacProxyInstaller = new PacProxyInstaller( - context, connectivityServiceInternalHandler, pacChangedEvent); + mPacProxyManager = context.getSystemService(PacProxyManager.class); + + PacProxyInstalledListener listener = new PacProxyInstalledListener(pacChangedEvent); + mPacProxyManager.addPacProxyInstalledListener( + new HandlerExecutor(mConnectivityServiceHandler), listener); } // Convert empty ProxyInfo's to null as null-checks are used to determine if proxies are present @@ -182,7 +201,7 @@ public class ProxyTracker { if (!TextUtils.isEmpty(pacFileUrl)) { mConnectivityServiceHandler.post( - () -> mPacProxyInstaller.setCurrentProxyScriptUrl(proxyProperties)); + () -> mPacProxyManager.setCurrentProxyScriptUrl(proxyProperties)); } } } @@ -226,9 +245,9 @@ public class ProxyTracker { final ProxyInfo defaultProxy = getDefaultProxy(); final ProxyInfo proxyInfo = null != defaultProxy ? defaultProxy : ProxyInfo.buildDirectProxy("", 0, Collections.emptyList()); + mPacProxyManager.setCurrentProxyScriptUrl(proxyInfo); - if (mPacProxyInstaller.setCurrentProxyScriptUrl(proxyInfo) - == PacProxyInstaller.DONT_SEND_BROADCAST) { + if (!shouldSendBroadcast(proxyInfo)) { return; } if (DBG) Log.d(TAG, "sending Proxy Broadcast for " + proxyInfo); @@ -244,6 +263,10 @@ public class ProxyTracker { } } + private boolean shouldSendBroadcast(ProxyInfo proxy) { + return Uri.EMPTY.equals(proxy.getPacFileUrl()) || proxy.getPort() > 0; + } + /** * Sets the global proxy in memory. Also writes the values to the global settings of the device. * @@ -308,10 +331,10 @@ public class ProxyTracker { return; } - // This call could be coming from the PacProxyInstaller, containing the port of the + // This call could be coming from the PacProxyService, containing the port of the // local proxy. If this new proxy matches the global proxy then copy this proxy to the // global (to get the correct local port), and send a broadcast. - // TODO: Switch PacProxyInstaller to have its own message to send back rather than + // TODO: Switch PacProxyService to have its own message to send back rather than // reusing EVENT_HAS_CHANGED_PROXY and this call to handleApplyDefaultProxy. if ((mGlobalProxy != null) && (proxyInfo != null) && (!Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 5fbf1c4e1f40..4e23609bd774 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -116,6 +116,7 @@ import com.android.server.camera.CameraServiceProxy; import com.android.server.clipboard.ClipboardService; import com.android.server.compat.PlatformCompat; import com.android.server.compat.PlatformCompatNative; +import com.android.server.connectivity.PacProxyService; import com.android.server.contentcapture.ContentCaptureManagerInternal; import com.android.server.coverage.CoverageService; import com.android.server.devicepolicy.DevicePolicyManagerService; @@ -1315,6 +1316,7 @@ public final class SystemServer implements Dumpable { ConsumerIrService consumerIr = null; MmsServiceBroker mmsService = null; HardwarePropertiesManagerService hardwarePropertiesService = null; + PacProxyService pacProxyService = null; boolean disableSystemTextClassifier = SystemProperties.getBoolean( "config.disable_systemtextclassifier", false); @@ -1874,6 +1876,15 @@ public final class SystemServer implements Dumpable { t.traceEnd(); } + t.traceBegin("StartPacProxyService"); + try { + pacProxyService = new PacProxyService(context); + ServiceManager.addService(Context.PAC_PROXY_SERVICE, pacProxyService); + } catch (Throwable e) { + reportWtf("starting PacProxyService", e); + } + t.traceEnd(); + t.traceBegin("StartConnectivityService"); // This has to be called after NetworkManagementService, NetworkStatsService // and NetworkPolicyManager because ConnectivityService needs to take these |