Merge "Move ipconfig file inside apex data directory" into tm-dev

This commit is contained in:
TreeHugger Robot
2022-05-20 12:30:41 +00:00
committed by Android (Google) Code Review
2 changed files with 220 additions and 18 deletions

View File

@@ -16,23 +16,37 @@
package com.android.server.ethernet; package com.android.server.ethernet;
import static com.android.net.module.util.DeviceConfigUtils.TETHERING_MODULE_NAME;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.ApexEnvironment;
import android.net.IpConfiguration; import android.net.IpConfiguration;
import android.os.Environment; import android.os.Environment;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.net.IpConfigStore; import com.android.server.net.IpConfigStore;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/** /**
* This class provides an API to store and manage Ethernet network configuration. * This class provides an API to store and manage Ethernet network configuration.
*/ */
public class EthernetConfigStore { public class EthernetConfigStore {
private static final String ipConfigFile = Environment.getDataDirectory() + private static final String TAG = EthernetConfigStore.class.getSimpleName();
"/misc/ethernet/ipconfig.txt"; private static final String CONFIG_FILE = "ipconfig.txt";
private static final String FILE_PATH = "/misc/ethernet/";
private static final String LEGACY_IP_CONFIG_FILE_PATH = Environment.getDataDirectory()
+ FILE_PATH;
private static final String APEX_IP_CONFIG_FILE_PATH = ApexEnvironment.getApexEnvironment(
TETHERING_MODULE_NAME).getDeviceProtectedDataDir() + FILE_PATH;
private IpConfigStore mStore = new IpConfigStore(); private IpConfigStore mStore = new IpConfigStore();
private ArrayMap<String, IpConfiguration> mIpConfigurations; private final ArrayMap<String, IpConfiguration> mIpConfigurations;
private IpConfiguration mIpConfigurationForDefaultInterface; private IpConfiguration mIpConfigurationForDefaultInterface;
private final Object mSync = new Object(); private final Object mSync = new Object();
@@ -40,22 +54,70 @@ public class EthernetConfigStore {
mIpConfigurations = new ArrayMap<>(0); mIpConfigurations = new ArrayMap<>(0);
} }
public void read() { private static boolean doesConfigFileExist(final String filepath) {
synchronized (mSync) { return new File(filepath).exists();
ArrayMap<String, IpConfiguration> configs = }
IpConfigStore.readIpConfigurations(ipConfigFile);
// This configuration may exist in old file versions when there was only a single active private void writeLegacyIpConfigToApexPath(final String newFilePath, final String oldFilePath,
// Ethernet interface. final String filename) {
if (configs.containsKey("0")) { final File directory = new File(newFilePath);
mIpConfigurationForDefaultInterface = configs.remove("0"); if (!directory.exists()) {
directory.mkdirs();
}
// Write the legacy IP config to the apex file path.
FileOutputStream fos = null;
final AtomicFile dst = new AtomicFile(new File(newFilePath + filename));
final AtomicFile src = new AtomicFile(new File(oldFilePath + filename));
try {
final byte[] raw = src.readFully();
if (raw.length > 0) {
fos = dst.startWrite();
fos.write(raw);
fos.flush();
dst.finishWrite(fos);
} }
} catch (IOException e) {
mIpConfigurations = configs; Log.e(TAG, "Fail to sync the legacy IP config to the apex file path.");
dst.failWrite(fos);
} }
} }
public void read() {
read(APEX_IP_CONFIG_FILE_PATH, LEGACY_IP_CONFIG_FILE_PATH, CONFIG_FILE);
}
@VisibleForTesting
void read(final String newFilePath, final String oldFilePath, final String filename) {
synchronized (mSync) {
// Attempt to read the IP configuration from apex file path first.
if (doesConfigFileExist(newFilePath + filename)) {
loadConfigFileLocked(newFilePath + filename);
return;
}
// If the config file doesn't exist in the apex file path, attempt to read it from
// the legacy file path, if config file exists, write the legacy IP configuration to
// apex config file path, this should just happen on the first boot. New or updated
// config entries are only written to the apex config file later.
if (!doesConfigFileExist(oldFilePath + filename)) return;
loadConfigFileLocked(oldFilePath + filename);
writeLegacyIpConfigToApexPath(newFilePath, oldFilePath, filename);
}
}
private void loadConfigFileLocked(final String filepath) {
final ArrayMap<String, IpConfiguration> configs =
IpConfigStore.readIpConfigurations(filepath);
mIpConfigurations.putAll(configs);
}
public void write(String iface, IpConfiguration config) { public void write(String iface, IpConfiguration config) {
write(iface, config, APEX_IP_CONFIG_FILE_PATH + CONFIG_FILE);
}
@VisibleForTesting
void write(String iface, IpConfiguration config, String filepath) {
boolean modified; boolean modified;
synchronized (mSync) { synchronized (mSync) {
@@ -67,7 +129,7 @@ public class EthernetConfigStore {
} }
if (modified) { if (modified) {
mStore.writeIpConfigurations(ipConfigFile, mIpConfigurations); mStore.writeIpConfigurations(filepath, mIpConfigurations);
} }
} }
} }
@@ -80,9 +142,6 @@ public class EthernetConfigStore {
@Nullable @Nullable
public IpConfiguration getIpConfigurationForDefaultInterface() { public IpConfiguration getIpConfigurationForDefaultInterface() {
synchronized (mSync) { return null;
return mIpConfigurationForDefaultInterface == null
? null : new IpConfiguration(mIpConfigurationForDefaultInterface);
}
} }
} }

View File

@@ -0,0 +1,143 @@
/*
* Copyright (C) 2022 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 com.android.server.ethernet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.content.Context;
import android.net.InetAddresses;
import android.net.IpConfiguration;
import android.net.IpConfiguration.IpAssignment;
import android.net.IpConfiguration.ProxySettings;
import android.net.LinkAddress;
import android.net.ProxyInfo;
import android.net.StaticIpConfiguration;
import android.util.ArrayMap;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
@RunWith(AndroidJUnit4.class)
public class EthernetConfigStoreTest {
private static final LinkAddress LINKADDR = new LinkAddress("192.168.1.100/25");
private static final InetAddress GATEWAY = InetAddresses.parseNumericAddress("192.168.1.1");
private static final InetAddress DNS1 = InetAddresses.parseNumericAddress("8.8.8.8");
private static final InetAddress DNS2 = InetAddresses.parseNumericAddress("8.8.4.4");
private static final StaticIpConfiguration STATIC_IP_CONFIG =
new StaticIpConfiguration.Builder()
.setIpAddress(LINKADDR)
.setGateway(GATEWAY)
.setDnsServers(new ArrayList<InetAddress>(
List.of(DNS1, DNS2)))
.build();
private static final ProxyInfo PROXY_INFO = ProxyInfo.buildDirectProxy("test", 8888);
private static final IpConfiguration APEX_IP_CONFIG =
new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null);
private static final IpConfiguration LEGACY_IP_CONFIG =
new IpConfiguration(IpAssignment.STATIC, ProxySettings.STATIC, STATIC_IP_CONFIG,
PROXY_INFO);
private EthernetConfigStore mEthernetConfigStore;
private File mApexTestDir;
private File mLegacyTestDir;
private File mApexConfigFile;
private File mLegacyConfigFile;
private void createTestDir() {
final Context context = InstrumentationRegistry.getContext();
final File baseDir = context.getFilesDir();
mApexTestDir = new File(baseDir.getPath() + "/apex");
mApexTestDir.mkdirs();
mLegacyTestDir = new File(baseDir.getPath() + "/legacy");
mLegacyTestDir.mkdirs();
}
@Before
public void setUp() {
createTestDir();
mEthernetConfigStore = new EthernetConfigStore();
}
@After
public void tearDown() {
mApexTestDir.delete();
mLegacyTestDir.delete();
}
private void assertConfigFileExist(final String filepath) {
assertTrue(new File(filepath).exists());
}
/** Wait for the delayed write operation completes. */
private void waitForMs(long ms) {
try {
Thread.sleep(ms);
} catch (final InterruptedException e) {
fail("Thread was interrupted");
}
}
@Test
public void testWriteIpConfigToApexFilePathAndRead() throws Exception {
// Write the config file to the apex file path, pretend the config file exits and
// check if IP config should be read from apex file path.
mApexConfigFile = new File(mApexTestDir.getPath(), "test.txt");
mEthernetConfigStore.write("eth0", APEX_IP_CONFIG, mApexConfigFile.getPath());
waitForMs(50);
mEthernetConfigStore.read(mApexTestDir.getPath(), mLegacyTestDir.getPath(), "/test.txt");
final ArrayMap<String, IpConfiguration> ipConfigurations =
mEthernetConfigStore.getIpConfigurations();
assertEquals(APEX_IP_CONFIG, ipConfigurations.get("eth0"));
mApexConfigFile.delete();
}
@Test
public void testWriteIpConfigToLegacyFilePathAndRead() throws Exception {
// Write the config file to the legacy file path, pretend the config file exits and
// check if IP config should be read from legacy file path.
mLegacyConfigFile = new File(mLegacyTestDir, "test.txt");
mEthernetConfigStore.write("0", LEGACY_IP_CONFIG, mLegacyConfigFile.getPath());
waitForMs(50);
mEthernetConfigStore.read(mApexTestDir.getPath(), mLegacyTestDir.getPath(), "/test.txt");
final ArrayMap<String, IpConfiguration> ipConfigurations =
mEthernetConfigStore.getIpConfigurations();
assertEquals(LEGACY_IP_CONFIG, ipConfigurations.get("0"));
// Check the same config file in apex file path is created.
assertConfigFileExist(mApexTestDir.getPath() + "/test.txt");
final File apexConfigFile = new File(mApexTestDir.getPath() + "/test.txt");
apexConfigFile.delete();
mLegacyConfigFile.delete();
}
}