| /* |
| * Copyright (C) 2016 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.util; |
| |
| import android.content.Context; |
| import android.net.INetd; |
| import android.os.RemoteException; |
| import android.os.ServiceManager; |
| import android.os.SystemClock; |
| import android.util.Log; |
| |
| |
| /** |
| * @hide |
| */ |
| public class NetdService { |
| private static final String TAG = NetdService.class.getSimpleName(); |
| private static final long BASE_TIMEOUT_MS = 100; |
| private static final long MAX_TIMEOUT_MS = 1000; |
| |
| |
| /** |
| * Return an INetd instance, or null if not available. |
| * |
| * It is the caller's responsibility to check for a null return value |
| * and to handle RemoteException errors from invocations on the returned |
| * interface if, for example, netd dies and is restarted. |
| * |
| * Returned instances of INetd should not be cached. |
| * |
| * @return an INetd instance or null. |
| */ |
| public static INetd getInstance() { |
| // NOTE: ServiceManager does no caching for the netd service, |
| // because netd is not one of the defined common services. |
| final INetd netdInstance = INetd.Stub.asInterface( |
| ServiceManager.getService(Context.NETD_SERVICE)); |
| if (netdInstance == null) { |
| Log.w(TAG, "WARNING: returning null INetd instance."); |
| } |
| return netdInstance; |
| } |
| |
| /** |
| * Blocks for a specified time until an INetd instance is available. |
| * |
| * It is the caller's responsibility to handle RemoteException errors |
| * from invocations on the returned interface if, for example, netd |
| * dies after this interface was returned. |
| * |
| * Returned instances of INetd should not be cached. |
| * |
| * Special values of maxTimeoutMs include: 0, meaning try to obtain an |
| * INetd instance only once, and -1 (or any value less than 0), meaning |
| * try to obtain an INetd instance indefinitely. |
| * |
| * @param maxTimeoutMs the maximum time to spend getting an INetd instance |
| * @return an INetd instance or null if no instance is available |
| * within |maxTimeoutMs| milliseconds. |
| */ |
| public static INetd get(long maxTimeoutMs) { |
| if (maxTimeoutMs == 0) return getInstance(); |
| |
| final long stop = (maxTimeoutMs > 0) |
| ? SystemClock.elapsedRealtime() + maxTimeoutMs |
| : Long.MAX_VALUE; |
| |
| long timeoutMs = 0; |
| while (true) { |
| final INetd netdInstance = getInstance(); |
| if (netdInstance != null) { |
| return netdInstance; |
| } |
| |
| final long remaining = stop - SystemClock.elapsedRealtime(); |
| if (remaining <= 0) break; |
| |
| // No netdInstance was received; sleep and retry. |
| timeoutMs = Math.min(timeoutMs + BASE_TIMEOUT_MS, MAX_TIMEOUT_MS); |
| timeoutMs = Math.min(timeoutMs, remaining); |
| try { |
| Thread.sleep(timeoutMs); |
| } catch (InterruptedException e) {} |
| } |
| return null; |
| } |
| |
| /** |
| * Blocks until an INetd instance is available. |
| * |
| * It is the caller's responsibility to handle RemoteException errors |
| * from invocations on the returned interface if, for example, netd |
| * dies after this interface was returned. |
| * |
| * Returned instances of INetd should not be cached. |
| * |
| * @return an INetd instance. |
| */ |
| public static INetd get() { |
| return get(-1); |
| } |
| |
| public static interface NetdCommand { |
| void run(INetd netd) throws RemoteException; |
| } |
| |
| /** |
| * Blocks until an INetd instance is availabe, and retries until either |
| * the command succeeds or a runtime exception is thrown. |
| */ |
| public static void run(NetdCommand cmd) { |
| while (true) { |
| try { |
| cmd.run(get()); |
| return; |
| } catch (RemoteException re) { |
| Log.e(TAG, "error communicating with netd: " + re); |
| } |
| } |
| } |
| } |