Loading core/proto/android/service/network_watchlist.proto 0 → 100644 +36 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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. */ syntax = "proto2"; package com.android.service; option java_multiple_files = true; // It will be used by com.android.server.net.watchlist.ReportEncoder to // generate network watchlist report. message NetworkWatchlistReportProto { optional int32 report_version = 1; optional string watchlist_config_hash = 2; repeated NetworkWatchlistAppResultProto app_result = 3; } message NetworkWatchlistAppResultProto { optional string app_digest = 1; optional bool encoded_result = 2; } services/core/java/com/android/server/net/watchlist/ReportEncoder.java +22 −47 Original line number Diff line number Diff line Loading @@ -19,38 +19,31 @@ package com.android.server.net.watchlist; import android.annotation.Nullable; import android.util.Log; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; import com.android.service.NetworkWatchlistReportProto; import com.android.service.NetworkWatchlistAppResultProto; import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; /** * Helper class to encode and generate serialized DP encoded watchlist report. * * <p>Serialized report data structure: * [4 bytes magic number][4_bytes_report_version_code][32_bytes_watchlist_hash] * [app_1_digest_byte_array][app_1_encoded_visited_cnc_byte] * [app_2_digest_byte_array][app_2_encoded_visited_cnc_byte] * ... * * Total size: 4 + 4 + 32 + (32+1)*N, where N = number of digests * Helper class to encode and generate serialized DP encoded watchlist proto report. */ class ReportEncoder { private static final String TAG = "ReportEncoder"; // Report header magic number private static final byte[] MAGIC_NUMBER = {(byte) 0x8D, (byte) 0x37, (byte) 0x0A, (byte) 0xAC}; // Report version number, as file format / parameters can be changed in later version, we need // to have versioning on watchlist report format private static final byte[] REPORT_VERSION = {(byte) 0x00, (byte) 0x01}; private static final int REPORT_VERSION = 1; private static final int WATCHLIST_HASH_SIZE = 32; private static final int APP_DIGEST_SIZE = 32; /** * Apply DP on watchlist results, and generate a serialized watchlist report ready to store Loading @@ -64,11 +57,10 @@ class ReportEncoder { } /** * Convert DP encoded watchlist report into byte[] format. * TODO: Serialize it using protobuf * Convert DP encoded watchlist report into proto format. * * @param encodedReportMap DP encoded watchlist report. * @return Watchlist report in byte[] format, which will be shared in Dropbox. Null if * @return Watchlist report in proto format, which will be shared in Dropbox. Null if * watchlist report cannot be generated. */ @Nullable Loading @@ -85,42 +77,25 @@ class ReportEncoder { Log.e(TAG, "Unexpected hash length"); return null; } final int reportMapSize = encodedReportMap.size(); final byte[] outputReport = new byte[MAGIC_NUMBER.length + REPORT_VERSION.length + WATCHLIST_HASH_SIZE + reportMapSize * (APP_DIGEST_SIZE + /* Result */ 1)]; final List<String> sortedKeys = new ArrayList(encodedReportMap.keySet()); Collections.sort(sortedKeys); int offset = 0; // Set magic number to report System.arraycopy(MAGIC_NUMBER, 0, outputReport, offset, MAGIC_NUMBER.length); offset += MAGIC_NUMBER.length; final ByteArrayOutputStream reportOutputStream = new ByteArrayOutputStream(); final ProtoOutputStream proto = new ProtoOutputStream(reportOutputStream); // Set report version to report System.arraycopy(REPORT_VERSION, 0, outputReport, offset, REPORT_VERSION.length); offset += REPORT_VERSION.length; // Set watchlist hash to report System.arraycopy(watchlistHash, 0, outputReport, offset, watchlistHash.length); offset += watchlistHash.length; proto.write(NetworkWatchlistReportProto.REPORT_VERSION, REPORT_VERSION); proto.write(NetworkWatchlistReportProto.WATCHLIST_CONFIG_HASH, HexDump.toHexString(watchlistHash)); // Set app digest, encoded_isPha pair to report for (int i = 0; i < reportMapSize; i++) { String key = sortedKeys.get(i); for (Map.Entry<String, Boolean> entry : encodedReportMap.entrySet()) { String key = entry.getKey(); byte[] digest = HexDump.hexStringToByteArray(key); boolean isPha = encodedReportMap.get(key); System.arraycopy(digest, 0, outputReport, offset, APP_DIGEST_SIZE); offset += digest.length; outputReport[offset] = (byte) (isPha ? 1 : 0); offset += 1; } if (outputReport.length != offset) { Log.e(TAG, "Watchlist report size does not match! Offset: " + offset + ", report size: " + outputReport.length); boolean encodedResult = entry.getValue(); long token = proto.start(NetworkWatchlistReportProto.APP_RESULT); proto.write(NetworkWatchlistAppResultProto.APP_DIGEST, key); proto.write(NetworkWatchlistAppResultProto.ENCODED_RESULT, encodedResult); proto.end(token); } return outputReport; proto.flush(); return reportOutputStream.toByteArray(); } } services/tests/servicestests/Android.mk +2 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ ShortcutManagerTestUtils \ truth-prebuilt \ testables \ testng testng \ platformprotosnano LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl Loading services/tests/servicestests/src/com/android/server/net/watchlist/ReportUtilsTests.java→services/tests/servicestests/src/com/android/server/net/watchlist/ReportEncoderTests.java +28 −25 Original line number Diff line number Diff line /* * Copyright 2017 The Android Open Source Project * Copyright (C) 2018 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. Loading @@ -16,15 +16,13 @@ package com.android.server.net.watchlist; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import com.android.internal.util.HexDump; import org.junit.After; import org.junit.Before; import org.junit.Test; Loading @@ -37,18 +35,21 @@ import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import com.android.service.nano.NetworkWatchlistReportProto; import com.android.service.nano.NetworkWatchlistAppResultProto; /** * runtest frameworks-services -c com.android.server.net.watchlist.ReportUtilsTests * runtest frameworks-services -c com.android.server.net.watchlist.ReportEncoderTests */ @RunWith(AndroidJUnit4.class) @SmallTest public class ReportUtilsTests { public class ReportEncoderTests { private static final String TEST_XML_1 = "NetworkWatchlistTest/watchlist_config_test1.xml"; private static final String TEST_XML_1_HASH = "C99F27A08B1FDB15B101098E12BB2A0AA0D474E23C50F24920A52AB2322BFD94"; private static final String REPORT_HEADER_MAGIC = "8D370AAC"; private static final String REPORT_HEADER_VERSION = "0001"; private static final int REPORT_VERSION = 1; private static final int EXPECTED_REPORT_VERSION = 1; private Context mContext; private File mTestXmlFile; Loading @@ -67,26 +68,28 @@ public class ReportUtilsTests { @Test public void testReportUtils_serializeReport() throws Exception { final byte[] expectedResult = HexDump.hexStringToByteArray( REPORT_HEADER_MAGIC + REPORT_HEADER_VERSION + TEST_XML_1_HASH + "B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43" + "01" + "C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB44" + "00" + "D86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB45" + "00" + "E86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB46" + "01" + "F86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB47" + "01" ); HashMap<String, Boolean> input = new HashMap<>(); input.put("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB44", false); input.put("B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43", true); input.put("D86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB45", false); input.put("E86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB46", true); input.put("F86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB47", true); HashMap<String, Boolean> map = new HashMap<>(); map.put("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB44", false); map.put("B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43", true); map.put("D86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB45", false); map.put("E86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB46", true); map.put("F86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB47", true); copyWatchlistConfigXml(mContext, TEST_XML_1, mTestXmlFile); WatchlistConfig config = new WatchlistConfig(mTestXmlFile); byte[] result = ReportEncoder.serializeReport(config, input); assertArrayEquals(expectedResult, result); final byte[] result = ReportEncoder.serializeReport(config, map); // Parse result back to NetworkWatchlistReportDumpProto final NetworkWatchlistReportProto reportProto = NetworkWatchlistReportProto.parseFrom(result); assertEquals(REPORT_VERSION, reportProto.reportVersion); assertEquals(TEST_XML_1_HASH, reportProto.watchlistConfigHash); assertEquals(map.size(), reportProto.appResult.length); for (NetworkWatchlistAppResultProto appProto : reportProto.appResult) { final String digest = appProto.appDigest; assertEquals(map.get(digest), appProto.encodedResult); } } private static void copyWatchlistConfigXml(Context context, String xmlAsset, File outFile) Loading Loading
core/proto/android/service/network_watchlist.proto 0 → 100644 +36 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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. */ syntax = "proto2"; package com.android.service; option java_multiple_files = true; // It will be used by com.android.server.net.watchlist.ReportEncoder to // generate network watchlist report. message NetworkWatchlistReportProto { optional int32 report_version = 1; optional string watchlist_config_hash = 2; repeated NetworkWatchlistAppResultProto app_result = 3; } message NetworkWatchlistAppResultProto { optional string app_digest = 1; optional bool encoded_result = 2; }
services/core/java/com/android/server/net/watchlist/ReportEncoder.java +22 −47 Original line number Diff line number Diff line Loading @@ -19,38 +19,31 @@ package com.android.server.net.watchlist; import android.annotation.Nullable; import android.util.Log; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; import com.android.service.NetworkWatchlistReportProto; import com.android.service.NetworkWatchlistAppResultProto; import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; /** * Helper class to encode and generate serialized DP encoded watchlist report. * * <p>Serialized report data structure: * [4 bytes magic number][4_bytes_report_version_code][32_bytes_watchlist_hash] * [app_1_digest_byte_array][app_1_encoded_visited_cnc_byte] * [app_2_digest_byte_array][app_2_encoded_visited_cnc_byte] * ... * * Total size: 4 + 4 + 32 + (32+1)*N, where N = number of digests * Helper class to encode and generate serialized DP encoded watchlist proto report. */ class ReportEncoder { private static final String TAG = "ReportEncoder"; // Report header magic number private static final byte[] MAGIC_NUMBER = {(byte) 0x8D, (byte) 0x37, (byte) 0x0A, (byte) 0xAC}; // Report version number, as file format / parameters can be changed in later version, we need // to have versioning on watchlist report format private static final byte[] REPORT_VERSION = {(byte) 0x00, (byte) 0x01}; private static final int REPORT_VERSION = 1; private static final int WATCHLIST_HASH_SIZE = 32; private static final int APP_DIGEST_SIZE = 32; /** * Apply DP on watchlist results, and generate a serialized watchlist report ready to store Loading @@ -64,11 +57,10 @@ class ReportEncoder { } /** * Convert DP encoded watchlist report into byte[] format. * TODO: Serialize it using protobuf * Convert DP encoded watchlist report into proto format. * * @param encodedReportMap DP encoded watchlist report. * @return Watchlist report in byte[] format, which will be shared in Dropbox. Null if * @return Watchlist report in proto format, which will be shared in Dropbox. Null if * watchlist report cannot be generated. */ @Nullable Loading @@ -85,42 +77,25 @@ class ReportEncoder { Log.e(TAG, "Unexpected hash length"); return null; } final int reportMapSize = encodedReportMap.size(); final byte[] outputReport = new byte[MAGIC_NUMBER.length + REPORT_VERSION.length + WATCHLIST_HASH_SIZE + reportMapSize * (APP_DIGEST_SIZE + /* Result */ 1)]; final List<String> sortedKeys = new ArrayList(encodedReportMap.keySet()); Collections.sort(sortedKeys); int offset = 0; // Set magic number to report System.arraycopy(MAGIC_NUMBER, 0, outputReport, offset, MAGIC_NUMBER.length); offset += MAGIC_NUMBER.length; final ByteArrayOutputStream reportOutputStream = new ByteArrayOutputStream(); final ProtoOutputStream proto = new ProtoOutputStream(reportOutputStream); // Set report version to report System.arraycopy(REPORT_VERSION, 0, outputReport, offset, REPORT_VERSION.length); offset += REPORT_VERSION.length; // Set watchlist hash to report System.arraycopy(watchlistHash, 0, outputReport, offset, watchlistHash.length); offset += watchlistHash.length; proto.write(NetworkWatchlistReportProto.REPORT_VERSION, REPORT_VERSION); proto.write(NetworkWatchlistReportProto.WATCHLIST_CONFIG_HASH, HexDump.toHexString(watchlistHash)); // Set app digest, encoded_isPha pair to report for (int i = 0; i < reportMapSize; i++) { String key = sortedKeys.get(i); for (Map.Entry<String, Boolean> entry : encodedReportMap.entrySet()) { String key = entry.getKey(); byte[] digest = HexDump.hexStringToByteArray(key); boolean isPha = encodedReportMap.get(key); System.arraycopy(digest, 0, outputReport, offset, APP_DIGEST_SIZE); offset += digest.length; outputReport[offset] = (byte) (isPha ? 1 : 0); offset += 1; } if (outputReport.length != offset) { Log.e(TAG, "Watchlist report size does not match! Offset: " + offset + ", report size: " + outputReport.length); boolean encodedResult = entry.getValue(); long token = proto.start(NetworkWatchlistReportProto.APP_RESULT); proto.write(NetworkWatchlistAppResultProto.APP_DIGEST, key); proto.write(NetworkWatchlistAppResultProto.ENCODED_RESULT, encodedResult); proto.end(token); } return outputReport; proto.flush(); return reportOutputStream.toByteArray(); } }
services/tests/servicestests/Android.mk +2 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ ShortcutManagerTestUtils \ truth-prebuilt \ testables \ testng testng \ platformprotosnano LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl Loading
services/tests/servicestests/src/com/android/server/net/watchlist/ReportUtilsTests.java→services/tests/servicestests/src/com/android/server/net/watchlist/ReportEncoderTests.java +28 −25 Original line number Diff line number Diff line /* * Copyright 2017 The Android Open Source Project * Copyright (C) 2018 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. Loading @@ -16,15 +16,13 @@ package com.android.server.net.watchlist; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import com.android.internal.util.HexDump; import org.junit.After; import org.junit.Before; import org.junit.Test; Loading @@ -37,18 +35,21 @@ import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import com.android.service.nano.NetworkWatchlistReportProto; import com.android.service.nano.NetworkWatchlistAppResultProto; /** * runtest frameworks-services -c com.android.server.net.watchlist.ReportUtilsTests * runtest frameworks-services -c com.android.server.net.watchlist.ReportEncoderTests */ @RunWith(AndroidJUnit4.class) @SmallTest public class ReportUtilsTests { public class ReportEncoderTests { private static final String TEST_XML_1 = "NetworkWatchlistTest/watchlist_config_test1.xml"; private static final String TEST_XML_1_HASH = "C99F27A08B1FDB15B101098E12BB2A0AA0D474E23C50F24920A52AB2322BFD94"; private static final String REPORT_HEADER_MAGIC = "8D370AAC"; private static final String REPORT_HEADER_VERSION = "0001"; private static final int REPORT_VERSION = 1; private static final int EXPECTED_REPORT_VERSION = 1; private Context mContext; private File mTestXmlFile; Loading @@ -67,26 +68,28 @@ public class ReportUtilsTests { @Test public void testReportUtils_serializeReport() throws Exception { final byte[] expectedResult = HexDump.hexStringToByteArray( REPORT_HEADER_MAGIC + REPORT_HEADER_VERSION + TEST_XML_1_HASH + "B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43" + "01" + "C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB44" + "00" + "D86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB45" + "00" + "E86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB46" + "01" + "F86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB47" + "01" ); HashMap<String, Boolean> input = new HashMap<>(); input.put("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB44", false); input.put("B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43", true); input.put("D86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB45", false); input.put("E86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB46", true); input.put("F86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB47", true); HashMap<String, Boolean> map = new HashMap<>(); map.put("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB44", false); map.put("B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43", true); map.put("D86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB45", false); map.put("E86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB46", true); map.put("F86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB47", true); copyWatchlistConfigXml(mContext, TEST_XML_1, mTestXmlFile); WatchlistConfig config = new WatchlistConfig(mTestXmlFile); byte[] result = ReportEncoder.serializeReport(config, input); assertArrayEquals(expectedResult, result); final byte[] result = ReportEncoder.serializeReport(config, map); // Parse result back to NetworkWatchlistReportDumpProto final NetworkWatchlistReportProto reportProto = NetworkWatchlistReportProto.parseFrom(result); assertEquals(REPORT_VERSION, reportProto.reportVersion); assertEquals(TEST_XML_1_HASH, reportProto.watchlistConfigHash); assertEquals(map.size(), reportProto.appResult.length); for (NetworkWatchlistAppResultProto appProto : reportProto.appResult) { final String digest = appProto.appDigest; assertEquals(map.get(digest), appProto.encodedResult); } } private static void copyWatchlistConfigXml(Context context, String xmlAsset, File outFile) Loading