1/*
2 * Copyright (C) 2014 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
17package com.android.server.ethernet;
18
19import android.content.Context;
20import android.content.pm.PackageManager;
21import android.net.IEthernetManager;
22import android.net.IEthernetServiceListener;
23import android.net.IpConfiguration;
24import android.net.IpConfiguration.IpAssignment;
25import android.net.IpConfiguration.ProxySettings;
26import android.os.Binder;
27import android.os.Handler;
28import android.os.HandlerThread;
29import android.os.RemoteCallbackList;
30import android.os.RemoteException;
31import android.provider.Settings;
32import android.util.Log;
33import android.util.PrintWriterPrinter;
34
35import com.android.internal.util.IndentingPrintWriter;
36
37import java.io.FileDescriptor;
38import java.io.PrintWriter;
39import java.util.concurrent.atomic.AtomicBoolean;
40
41/**
42 * EthernetServiceImpl handles remote Ethernet operation requests by implementing
43 * the IEthernetManager interface.
44 *
45 * @hide
46 */
47public class EthernetServiceImpl extends IEthernetManager.Stub {
48    private static final String TAG = "EthernetServiceImpl";
49
50    private final Context mContext;
51    private final EthernetConfigStore mEthernetConfigStore;
52    private final AtomicBoolean mStarted = new AtomicBoolean(false);
53    private IpConfiguration mIpConfiguration;
54
55    private Handler mHandler;
56    private final EthernetNetworkFactory mTracker;
57    private final RemoteCallbackList<IEthernetServiceListener> mListeners =
58            new RemoteCallbackList<IEthernetServiceListener>();
59
60    public EthernetServiceImpl(Context context) {
61        mContext = context;
62        Log.i(TAG, "Creating EthernetConfigStore");
63        mEthernetConfigStore = new EthernetConfigStore();
64        mIpConfiguration = mEthernetConfigStore.readIpAndProxyConfigurations();
65
66        Log.i(TAG, "Read stored IP configuration: " + mIpConfiguration);
67
68        mTracker = new EthernetNetworkFactory(mListeners);
69    }
70
71    private void enforceAccessPermission() {
72        mContext.enforceCallingOrSelfPermission(
73                android.Manifest.permission.ACCESS_NETWORK_STATE,
74                "EthernetService");
75    }
76
77    private void enforceConnectivityInternalPermission() {
78        mContext.enforceCallingOrSelfPermission(
79                android.Manifest.permission.CONNECTIVITY_INTERNAL,
80                "ConnectivityService");
81    }
82
83    public void start() {
84        Log.i(TAG, "Starting Ethernet service");
85
86        HandlerThread handlerThread = new HandlerThread("EthernetServiceThread");
87        handlerThread.start();
88        mHandler = new Handler(handlerThread.getLooper());
89
90        mTracker.start(mContext, mHandler);
91
92        mStarted.set(true);
93    }
94
95    /**
96     * Get Ethernet configuration
97     * @return the Ethernet Configuration, contained in {@link IpConfiguration}.
98     */
99    @Override
100    public IpConfiguration getConfiguration() {
101        enforceAccessPermission();
102
103        synchronized (mIpConfiguration) {
104            return new IpConfiguration(mIpConfiguration);
105        }
106    }
107
108    /**
109     * Set Ethernet configuration
110     */
111    @Override
112    public void setConfiguration(IpConfiguration config) {
113        if (!mStarted.get()) {
114            Log.w(TAG, "System isn't ready enough to change ethernet configuration");
115        }
116
117        enforceConnectivityInternalPermission();
118
119        synchronized (mIpConfiguration) {
120            mEthernetConfigStore.writeIpAndProxyConfigurations(config);
121
122            // TODO: this does not check proxy settings, gateways, etc.
123            // Fix this by making IpConfiguration a complete representation of static configuration.
124            if (!config.equals(mIpConfiguration)) {
125                mIpConfiguration = new IpConfiguration(config);
126                mTracker.stop();
127                mTracker.start(mContext, mHandler);
128            }
129        }
130    }
131
132    /**
133     * Indicates whether the system currently has one or more
134     * Ethernet interfaces.
135     */
136    @Override
137    public boolean isAvailable() {
138        enforceAccessPermission();
139        return mTracker.isTrackingInterface();
140    }
141
142    /**
143     * Addes a listener.
144     * @param listener A {@link IEthernetServiceListener} to add.
145     */
146    public void addListener(IEthernetServiceListener listener) {
147        if (listener == null) {
148            throw new IllegalArgumentException("listener must not be null");
149        }
150        enforceAccessPermission();
151        mListeners.register(listener);
152    }
153
154    /**
155     * Removes a listener.
156     * @param listener A {@link IEthernetServiceListener} to remove.
157     */
158    public void removeListener(IEthernetServiceListener listener) {
159        if (listener == null) {
160            throw new IllegalArgumentException("listener must not be null");
161        }
162        enforceAccessPermission();
163        mListeners.unregister(listener);
164    }
165
166    @Override
167    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
168        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
169        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
170                != PackageManager.PERMISSION_GRANTED) {
171            pw.println("Permission Denial: can't dump EthernetService from pid="
172                    + Binder.getCallingPid()
173                    + ", uid=" + Binder.getCallingUid());
174            return;
175        }
176
177        pw.println("Current Ethernet state: ");
178        pw.increaseIndent();
179        mTracker.dump(fd, pw, args);
180        pw.decreaseIndent();
181
182        pw.println();
183        pw.println("Stored Ethernet configuration: ");
184        pw.increaseIndent();
185        pw.println(mIpConfiguration);
186        pw.decreaseIndent();
187
188        pw.println("Handler:");
189        pw.increaseIndent();
190        mHandler.dump(new PrintWriterPrinter(pw), "EthernetServiceImpl");
191        pw.decreaseIndent();
192    }
193}
194