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