diff --git a/packages/SettingsProvider/src/com/android/providers/settings/NetworkPolicySerializer.java b/packages/SettingsProvider/src/com/android/providers/settings/NetworkPolicySerializer.java new file mode 100644 index 0000000000000..4b87da483b11a --- /dev/null +++ b/packages/SettingsProvider/src/com/android/providers/settings/NetworkPolicySerializer.java @@ -0,0 +1,186 @@ +package com.android.providers.settings; + +import android.net.NetworkPolicy; +import android.net.NetworkTemplate; +import android.util.Log; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Backup/Restore Serializer Class for android.net.NetworkPolicy + */ +public class NetworkPolicySerializer { + private static final boolean DEBUG = false; + private static final String TAG = "NetworkPolicySerializer"; + + private static final int NULL = 0; + private static final int NOT_NULL = 1; + /** + * Current Version of the Serializer. + */ + private static int STATE_VERSION = 1; + + /** + * Marshals an array of NetworkPolicy objects into a byte-array. + * + * @param policies - NetworkPolicies to be Marshaled + * @return byte array + */ + + public static byte[] marshalNetworkPolicies(NetworkPolicy policies[]) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + if (policies != null && policies.length != 0) { + DataOutputStream out = new DataOutputStream(baos); + try { + out.writeInt(STATE_VERSION); + out.writeInt(policies.length); + for (NetworkPolicy policy : policies) { + byte[] marshaledPolicy = marshalNetworkPolicy(policy); + if (marshaledPolicy != null) { + out.writeByte(NOT_NULL); + out.writeInt(marshaledPolicy.length); + out.write(marshaledPolicy); + } else { + out.writeByte(NULL); + } + } + } catch (IOException ioe) { + Log.e(TAG, "Failed to Convert NetworkPolicies to byte array", ioe); + baos.reset(); + } + } + return baos.toByteArray(); + } + + /** + * Unmarshals a byte array into an array of NetworkPolicy Objects + * + * @param data - marshaled NetworkPolicies Array + * @return NetworkPolicy[] array + */ + public static NetworkPolicy[] unmarshalNetworkPolicies(byte[] data) { + if (data == null || data.length == 0) { + return new NetworkPolicy[0]; + } + DataInputStream in = new DataInputStream(new ByteArrayInputStream(data)); + try { + int version = in.readInt(); + int length = in.readInt(); + NetworkPolicy[] policies = new NetworkPolicy[length]; + for (int i = 0; i < length; i++) { + byte isNull = in.readByte(); + if (isNull == NULL) continue; + int byteLength = in.readInt(); + byte[] policyData = new byte[byteLength]; + in.read(policyData, 0, byteLength); + policies[i] = unmarshalNetworkPolicy(policyData); + } + return policies; + } catch (IOException ioe) { + Log.e(TAG, "Failed to Convert byte array to NetworkPolicies", ioe); + return new NetworkPolicy[0]; + } + } + + /** + * Marshals a NetworkPolicy object into a byte-array. + * + * @param networkPolicy - NetworkPolicy to be Marshaled + * @return byte array + */ + public static byte[] marshalNetworkPolicy(NetworkPolicy networkPolicy) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + if (networkPolicy != null) { + DataOutputStream out = new DataOutputStream(baos); + try { + out.writeInt(STATE_VERSION); + writeNetworkTemplate(out, networkPolicy.template); + out.writeInt(networkPolicy.cycleDay); + writeString(out, networkPolicy.cycleTimezone); + out.writeLong(networkPolicy.warningBytes); + out.writeLong(networkPolicy.limitBytes); + out.writeLong(networkPolicy.lastWarningSnooze); + out.writeLong(networkPolicy.lastLimitSnooze); + out.writeInt(networkPolicy.metered ? 1 : 0); + out.writeInt(networkPolicy.inferred ? 1 : 0); + } catch (IOException ioe) { + Log.e(TAG, "Failed to Convert NetworkPolicy to byte array", ioe); + baos.reset(); + } + } + return baos.toByteArray(); + } + + /** + * Unmarshals a byte array into a NetworkPolicy Object + * + * @param data - marshaled NetworkPolicy Object + * @return NetworkPolicy Object + */ + public static NetworkPolicy unmarshalNetworkPolicy(byte[] data) { + if (data == null || data.length == 0) { + return null; + } + DataInputStream in = new DataInputStream(new ByteArrayInputStream(data)); + try { + int version = in.readInt(); + NetworkTemplate template = readNetworkTemplate(in, version); + int cycleDay = in.readInt(); + String cycleTimeZone = readString(in, version); + long warningBytes = in.readLong(); + long limitBytes = in.readLong(); + long lastWarningSnooze = in.readLong(); + long lastLimitSnooze = in.readLong(); + boolean metered = in.readInt() == 1; + boolean inferred = in.readInt() == 1; + return new NetworkPolicy(template, cycleDay, cycleTimeZone, warningBytes, limitBytes, + lastWarningSnooze, lastLimitSnooze, metered, inferred); + } catch (IOException ioe) { + Log.e(TAG, "Failed to Convert byte array to NetworkPolicy", ioe); + return null; + } + } + + private static NetworkTemplate readNetworkTemplate(DataInputStream in, int version) + throws IOException { + byte isNull = in.readByte(); + if (isNull == NULL) return null; + int matchRule = in.readInt(); + String subscriberId = readString(in, version); + String networkId = readString(in, version); + return new NetworkTemplate(matchRule, subscriberId, networkId); + } + + private static void writeNetworkTemplate(DataOutputStream out, NetworkTemplate template) + throws IOException { + if (template != null) { + out.writeByte(NOT_NULL); + out.writeInt(template.getMatchRule()); + writeString(out, template.getSubscriberId()); + writeString(out, template.getNetworkId()); + } else { + out.writeByte(NULL); + } + } + + private static String readString(DataInputStream in, int version) throws IOException { + byte isNull = in.readByte(); + if (isNull == NOT_NULL) { + return in.readUTF(); + } + return null; + } + + private static void writeString(DataOutputStream out, String val) throws IOException { + if (val != null) { + out.writeByte(NOT_NULL); + out.writeUTF(val); + } else { + out.writeByte(NULL); + } + } +} diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index 8910af458d6ff..185a03fc2e66e 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -24,6 +24,7 @@ import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; +import android.net.NetworkPolicyManager; import android.net.Uri; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.KeyMgmt; @@ -82,10 +83,12 @@ public class SettingsBackupAgent extends BackupAgentHelper { private static final String KEY_LOCALE = "locale"; private static final String KEY_LOCK_SETTINGS = "lock_settings"; private static final String KEY_SOFTAP_CONFIG = "softap_config"; + private static final String KEY_NET_POLICIES = "network_policies"; + // Versioning of the state file. Increment this version // number any time the set of state items is altered. - private static final int STATE_VERSION = 5; + private static final int STATE_VERSION = 6; // Slots in the checksum array. Never insert new items in the middle // of this array; new slots must be appended. @@ -97,8 +100,9 @@ public class SettingsBackupAgent extends BackupAgentHelper { private static final int STATE_GLOBAL = 5; private static final int STATE_LOCK_SETTINGS = 6; private static final int STATE_SOFTAP_CONFIG = 7; + private static final int STATE_NET_POLICIES = 8; - private static final int STATE_SIZE = 8; // The current number of state items + private static final int STATE_SIZE = 9; // The current number of state items // Number of entries in the checksum array at various version numbers private static final int STATE_SIZES[] = { @@ -107,7 +111,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { 5, // version 2 added STATE_WIFI_CONFIG 6, // version 3 added STATE_GLOBAL 7, // version 4 added STATE_LOCK_SETTINGS - STATE_SIZE // version 5 added STATE_SOFTAP_CONFIG + 8, // version 5 added STATE_SOFTAP_CONFIG + STATE_SIZE // version 6 added STATE_NET_POLICIES }; // Versioning of the 'full backup' format @@ -115,6 +120,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { private static final int FULL_BACKUP_ADDED_GLOBAL = 2; // added the "global" entry private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry + private static final int FULL_BACKUP_ADDED_NET_POLICIES = 5; //added the "network_policies" entry private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE; @@ -410,6 +416,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT); byte[] wifiConfigData = getFileData(mWifiConfigFile); byte[] softApConfigData = getSoftAPConfiguration(); + byte[] netPoliciesData = getNetworkPolicies(); long[] stateChecksums = readOldChecksums(oldState); @@ -433,6 +440,9 @@ public class SettingsBackupAgent extends BackupAgentHelper { stateChecksums[STATE_SOFTAP_CONFIG] = writeIfChanged(stateChecksums[STATE_SOFTAP_CONFIG], KEY_SOFTAP_CONFIG, softApConfigData, data); + stateChecksums[STATE_NET_POLICIES] = + writeIfChanged(stateChecksums[STATE_NET_POLICIES], KEY_NET_POLICIES, + netPoliciesData, data); writeNewChecksums(stateChecksums, newState); } @@ -573,6 +583,10 @@ public class SettingsBackupAgent extends BackupAgentHelper { byte[] softapData = new byte[size]; data.readEntityData(softapData, 0, size); restoreSoftApConfiguration(softapData); + } else if (KEY_NET_POLICIES.equals(key)) { + byte[] netPoliciesData = new byte[size]; + data.readEntityData(netPoliciesData, 0, size); + restoreNetworkPolicies(netPoliciesData); } else { data.skipEntityData(); } @@ -602,6 +616,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT); byte[] wifiConfigData = getFileData(mWifiConfigFile); byte[] softApConfigData = getSoftAPConfiguration(); + byte[] netPoliciesData = getNetworkPolicies(); // Write the data to the staging file, then emit that as our tarfile // representation of the backed-up settings. @@ -639,6 +654,9 @@ public class SettingsBackupAgent extends BackupAgentHelper { if (DEBUG_BACKUP) Log.d(TAG, softApConfigData.length + " bytes of softap config data"); out.writeInt(softApConfigData.length); out.write(softApConfigData); + if (DEBUG_BACKUP) Log.d(TAG, netPoliciesData.length + " bytes of network policies data"); + out.writeInt(netPoliciesData.length); + out.write(netPoliciesData); out.flush(); // also flushes downstream @@ -741,6 +759,16 @@ public class SettingsBackupAgent extends BackupAgentHelper { } } + if (version >= FULL_BACKUP_ADDED_NET_POLICIES){ + nBytes = in.readInt(); + if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of network policies data"); + if (nBytes > buffer.length) buffer = new byte[nBytes]; + if (nBytes > 0) { + in.readFully(buffer, 0, nBytes); + restoreNetworkPolicies(buffer); + } + } + if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete."); } else { data.close(); @@ -1196,6 +1224,20 @@ public class SettingsBackupAgent extends BackupAgentHelper { wifiManager.setWifiApConfiguration(WiFiConfigurationSerializer.unmarshalWifiConfig(data)); } + private byte[] getNetworkPolicies(){ + NetworkPolicyManager networkPolicyManager = + (NetworkPolicyManager)getSystemService(NETWORK_POLICY_SERVICE); + return NetworkPolicySerializer + .marshalNetworkPolicies(networkPolicyManager.getNetworkPolicies()); + } + + private void restoreNetworkPolicies(byte[] data){ + NetworkPolicyManager networkPolicyManager = + (NetworkPolicyManager)getSystemService(NETWORK_POLICY_SERVICE); + networkPolicyManager + .setNetworkPolicies(NetworkPolicySerializer.unmarshalNetworkPolicies(data)); + } + /** * Write an int in BigEndian into the byte array. * @param out byte array @@ -1217,11 +1259,10 @@ public class SettingsBackupAgent extends BackupAgentHelper { } private int readInt(byte[] in, int pos) { - int result = - ((in[pos ] & 0xFF) << 24) | - ((in[pos + 1] & 0xFF) << 16) | - ((in[pos + 2] & 0xFF) << 8) | - ((in[pos + 3] & 0xFF) << 0); + int result = ((in[pos ] & 0xFF) << 24) | + ((in[pos + 1] & 0xFF) << 16) | + ((in[pos + 2] & 0xFF) << 8) | + ((in[pos + 3] & 0xFF) << 0); return result; } @@ -1238,4 +1279,4 @@ public class SettingsBackupAgent extends BackupAgentHelper { } return WifiManager.WIFI_STATE_UNKNOWN; } -} \ No newline at end of file +} diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk index ef863e7df0c2e..f2789678debe6 100644 --- a/packages/SettingsProvider/test/Android.mk +++ b/packages/SettingsProvider/test/Android.mk @@ -5,7 +5,10 @@ include $(CLEAR_VARS) # Note we statically link SettingsState to do some unit tests. It's not accessible otherwise # because this test is not an instrumentation test. (because the target runs in the system process.) LOCAL_SRC_FILES := $(call all-subdir-java-files) \ - ../src/com/android/providers/settings/SettingsState.java + ../src/com/android/providers/settings/SettingsState.java \ + ../src/com/android/providers/settings/WiFiConfigurationSerializer.java \ + ../src/com/android/providers/settings/NetworkPolicySerializer.java + LOCAL_PACKAGE_NAME := SettingsProviderTest @@ -13,4 +16,4 @@ LOCAL_MODULE_TAGS := tests LOCAL_CERTIFICATE := platform -include $(BUILD_PACKAGE) \ No newline at end of file +include $(BUILD_PACKAGE) diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/NetworkPolicySerializerTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/NetworkPolicySerializerTest.java new file mode 100644 index 0000000000000..1986596f4ef10 --- /dev/null +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/NetworkPolicySerializerTest.java @@ -0,0 +1,117 @@ +package com.android.providers.settings; + +import android.net.NetworkPolicy; +import android.net.NetworkTemplate; +import android.test.AndroidTestCase; + +import java.util.Random; + +/** + * Tests for NetworkPolicySerializer + */ +public class NetworkPolicySerializerTest extends AndroidTestCase { + static Random sRandom = new Random(); + + public void testMarshallAndUnmarshalNetworkPolicy() { + NetworkPolicy policy = getDummyNetworkPolicy(); + byte[] data = NetworkPolicySerializer.marshalNetworkPolicy(policy); + assertNotNull("Got Null data from marshal", data); + assertFalse("Got back an empty byte[] from marshal", data.length == 0); + + NetworkPolicy unmarshaled = NetworkPolicySerializer.unmarshalNetworkPolicy(data); + assertNotNull("Got Null data from unmarshaled", unmarshaled); + assertTrue("NetworkPolicy Marshall and Unmarshal Failed!", policy.equals(unmarshaled)); + } + + public void testMarshallNetworkPolicyEdgeCases() { + byte[] data = NetworkPolicySerializer.marshalNetworkPolicy(null); + assertNotNull("NetworkPolicy marshal returned null. Expected: byte[0]", data); + assertEquals("NetworkPolicy marshal returned incomplete byte array. Expected: byte[0]", + data.length, 0); + } + + public void testUnmarshallNetworkPolicyEdgeCases() { + NetworkPolicy policy = NetworkPolicySerializer.unmarshalNetworkPolicy(null); + assertNull("Non null NetworkPolicy returned for null byte[] input", policy); + + policy = NetworkPolicySerializer.unmarshalNetworkPolicy(new byte[0]); + assertNull("Non null NetworkPolicy returned for empty byte[] input", policy); + + policy = NetworkPolicySerializer.unmarshalNetworkPolicy(new byte[]{10, 20, 30, 40, 50, 60}); + assertNull("Non null NetworkPolicy returned for incomplete byte[] input", policy); + } + + public void testMarshallAndUnmarshalNetworkPolicies() { + NetworkPolicy[] policies = getDummyNetworkPolicies(5); + byte[] data = NetworkPolicySerializer.marshalNetworkPolicies(policies); + assertNotNull("Got Null data from marshal", data); + assertFalse("Got back an empty byte[] from marshal", data.length == 0); + + NetworkPolicy[] unmarshaled = NetworkPolicySerializer.unmarshalNetworkPolicies(data); + assertNotNull("Got Null data from unmarshaled", unmarshaled); + try { + for (int i = 0; i < policies.length; i++) { + assertTrue("NetworkPolicies Marshall and Unmarshal Failed!", + policies[i].equals(unmarshaled[i])); + } + } catch (NullPointerException npe) { + assertTrue("Some policies were not marshaled/unmarshaled correctly", false); + } + } + + public void testMarshallNetworkPoliciesEdgeCases() { + byte[] data = NetworkPolicySerializer.marshalNetworkPolicies(null); + assertNotNull("NetworkPolicies marshal returned null!", data); + assertEquals("NetworkPolicies marshal returned incomplete byte array", data.length, 0); + + data = NetworkPolicySerializer.marshalNetworkPolicies(new NetworkPolicy[0]); + assertNotNull("NetworkPolicies marshal returned null for empty NetworkPolicy[]", data); + assertEquals("NetworkPolicies marshal returned incomplete byte array for empty NetworkPolicy[]" + , data.length, 0); + } + + public void testUnmarshalNetworkPoliciesEdgeCases() { + NetworkPolicy[] policies = NetworkPolicySerializer.unmarshalNetworkPolicies(null); + assertNotNull("NetworkPolicies unmarshal returned null for null input. Expected: byte[0] ", + policies); + assertEquals("Non Empty NetworkPolicy[] returned for null input Expected: byte[0]", + policies.length, 0); + + policies = NetworkPolicySerializer.unmarshalNetworkPolicies(new byte[0]); + assertNotNull("NetworkPolicies unmarshal returned null for empty byte[] input. Expected: byte[0]", + policies); + assertEquals("Non Empty NetworkPolicy[] returned for empty byte[] input. Expected: byte[0]", + policies.length, 0); + + policies = NetworkPolicySerializer.unmarshalNetworkPolicies(new byte[]{10, 20, 30, 40, 50, 60}); + assertNotNull("NetworkPolicies unmarshal returned null for incomplete byte[] input. " + + "Expected: byte[0] ", policies); + assertEquals("Non Empty NetworkPolicy[] returned for incomplete byte[] input Expected: byte[0]", + policies.length, 0); + + } + + private NetworkPolicy[] getDummyNetworkPolicies(int num) { + NetworkPolicy[] policies = new NetworkPolicy[num]; + for (int i = 0; i < num; i++) { + policies[i] = getDummyNetworkPolicy(); + } + return policies; + } + + private NetworkPolicy getDummyNetworkPolicy() { + NetworkTemplate template = new NetworkTemplate(NetworkTemplate.MATCH_MOBILE_ALL, "subId", + "GoogleGuest"); + int cycleDay = sRandom.nextInt(); + String cycleTimezone = "timezone"; + long warningBytes = sRandom.nextLong(); + long limitBytes = sRandom.nextLong(); + long lastWarningSnooze = sRandom.nextLong(); + long lastLimitSnooze = sRandom.nextLong(); + boolean metered = sRandom.nextInt() % 2 == 0; + boolean inferred = sRandom.nextInt() % 2 == 0; + return new NetworkPolicy(template, cycleDay, cycleTimezone, warningBytes, limitBytes, + lastWarningSnooze, lastLimitSnooze, metered, inferred); + } + +}