Merge "Move ipconfig file inside apex data directory" into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
9f57db4bda
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean doesConfigFileExist(final String filepath) {
|
||||||
|
return new File(filepath).exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeLegacyIpConfigToApexPath(final String newFilePath, final String oldFilePath,
|
||||||
|
final String filename) {
|
||||||
|
final File directory = new File(newFilePath);
|
||||||
|
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) {
|
||||||
|
Log.e(TAG, "Fail to sync the legacy IP config to the apex file path.");
|
||||||
|
dst.failWrite(fos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void read() {
|
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) {
|
synchronized (mSync) {
|
||||||
ArrayMap<String, IpConfiguration> configs =
|
// Attempt to read the IP configuration from apex file path first.
|
||||||
IpConfigStore.readIpConfigurations(ipConfigFile);
|
if (doesConfigFileExist(newFilePath + filename)) {
|
||||||
|
loadConfigFileLocked(newFilePath + filename);
|
||||||
// This configuration may exist in old file versions when there was only a single active
|
return;
|
||||||
// Ethernet interface.
|
|
||||||
if (configs.containsKey("0")) {
|
|
||||||
mIpConfigurationForDefaultInterface = configs.remove("0");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mIpConfigurations = configs;
|
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user