Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b0558905 authored by Ricky Wai's avatar Ricky Wai Committed by Android (Google) Code Review
Browse files

Merge "Add adb command to force generate network watchlist report for testing" into pi-dev

parents 822dfea6 fda8ec03
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.privacy.internal.longitudinalreporting;
import android.privacy.DifferentialPrivacyEncoder;
import android.privacy.internal.rappor.RapporConfig;
import android.privacy.internal.rappor.RapporEncoder;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;

@@ -48,6 +49,9 @@ import com.android.internal.annotations.VisibleForTesting;
 */
public class LongitudinalReportingEncoder implements DifferentialPrivacyEncoder {

    private static final String TAG = "LongitudinalEncoder";
    private static final boolean DEBUG = false;

    // Suffix that will be added to Rappor's encoder id. There's a (relatively) small risk some
    // other Rappor encoder may re-use the same encoder id.
    private static final String PRR1_ENCODER_ID = "prr1_encoder_id";
@@ -121,11 +125,18 @@ public class LongitudinalReportingEncoder implements DifferentialPrivacyEncoder

    @Override
    public byte[] encodeBoolean(boolean original) {
        if (DEBUG) {
            Log.d(TAG, "encodeBoolean, encoderId:" + mConfig.getEncoderId() + ", original: "
                    + original);
        }
        if (mFakeValue != null) {
            // Use the fake value generated in PRR.
            original = mFakeValue.booleanValue();
            if (DEBUG) Log.d(TAG, "Use fake value: " + original);
        }
        return mIRREncoder.encodeBoolean(original);
        byte[] result = mIRREncoder.encodeBoolean(original);
        if (DEBUG) Log.d(TAG, "result: " + ((result[0] & 0x1) != 0));
        return result;
    }

    @Override
+16 −1
Original line number Diff line number Diff line
@@ -171,7 +171,7 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub {
            Slog.w(TAG, "Only shell is allowed to call network watchlist shell commands");
            return;
        }
        (new NetworkWatchlistShellCommand(mContext)).exec(this, in, out, err, args, callback,
        (new NetworkWatchlistShellCommand(this, mContext)).exec(this, in, out, err, args, callback,
                resultReceiver);
    }

@@ -262,6 +262,21 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub {
        mNetworkWatchlistHandler.reportWatchlistIfNecessary();
    }

    /**
     * Force generate watchlist report for testing.
     *
     * @param lastReportTime Watchlist report will cotain all records before this time.
     * @return True if operation success.
     */
    public boolean forceReportWatchlistForTest(long lastReportTime) {
        if (mConfig.isConfigSecure()) {
            // Should not force generate report under production config.
            return false;
        }
        mNetworkWatchlistHandler.forceReportWatchlistForTest(lastReportTime);
        return true;
    }

    @Override
    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+37 −9
Original line number Diff line number Diff line
@@ -19,9 +19,11 @@ package com.android.server.net.watchlist;
import android.content.Context;
import android.content.Intent;
import android.net.NetworkWatchlistManager;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.provider.Settings;

import java.io.FileInputStream;
import java.io.IOException;
@@ -34,10 +36,12 @@ import java.io.PrintWriter;
 */
class NetworkWatchlistShellCommand extends ShellCommand {

    final NetworkWatchlistManager mNetworkWatchlistManager;
    final Context mContext;
    final NetworkWatchlistService mService;

    NetworkWatchlistShellCommand(Context context) {
        mNetworkWatchlistManager = new NetworkWatchlistManager(context);
    NetworkWatchlistShellCommand(NetworkWatchlistService service, Context context) {
        mContext = context;
        mService = service;
    }

    @Override
@@ -51,11 +55,13 @@ class NetworkWatchlistShellCommand extends ShellCommand {
            switch(cmd) {
                case "set-test-config":
                    return runSetTestConfig();
                case "force-generate-report":
                    return runForceGenerateReport();
                default:
                    return handleDefaultCommands(cmd);
            }
        } catch (RemoteException e) {
            pw.println("Remote exception: " + e);
        } catch (Exception e) {
            pw.println("Exception: " + e);
        }
        return -1;
    }
@@ -73,22 +79,44 @@ class NetworkWatchlistShellCommand extends ShellCommand {
                WatchlistConfig.getInstance().setTestMode(fileStream);
            }
            pw.println("Success!");
        } catch (RuntimeException | IOException ex) {
        } catch (Exception ex) {
            pw.println("Error: " + ex.toString());
            return -1;
        }
        return 0;
    }

    private int runForceGenerateReport() throws RemoteException {
        final PrintWriter pw = getOutPrintWriter();
        final long ident = Binder.clearCallingIdentity();
        try {
            // Reset last report time
            if (!WatchlistConfig.getInstance().isConfigSecure()) {
                pw.println("Error: Cannot force generate report under production config");
                return -1;
            }
            Settings.Global.putLong(mContext.getContentResolver(),
                    Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME, 0L);
            mService.forceReportWatchlistForTest(System.currentTimeMillis());
            pw.println("Success!");
        } catch (Exception ex) {
            pw.println("Error: " + ex);
            return -1;
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
        return 0;
    }

    @Override
    public void onHelp() {
        final PrintWriter pw = getOutPrintWriter();
        pw.println("Network watchlist manager commands:");
        pw.println("  help");
        pw.println("    Print this help text.");
        pw.println("");
        pw.println("  set-test-config your_watchlist_config.xml");
        pw.println();
        Intent.printIntentArgsHelp(pw , "");
        pw.println("    Set network watchlist test config file.");
        pw.println("  force-generate-report");
        pw.println("    Force generate watchlist test report.");
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.net.watchlist;
import android.privacy.DifferentialPrivacyEncoder;
import android.privacy.internal.longitudinalreporting.LongitudinalReportingConfig;
import android.privacy.internal.longitudinalreporting.LongitudinalReportingEncoder;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;

@@ -32,6 +33,7 @@ import java.util.Map;
class PrivacyUtils {

    private static final String TAG = "PrivacyUtils";
    private static final boolean DEBUG = NetworkWatchlistService.DEBUG;

    /**
     * Parameters used for encoding watchlist reports.
@@ -84,6 +86,7 @@ class PrivacyUtils {
    @VisibleForTesting
    static Map<String, Boolean> createDpEncodedReportMap(boolean isSecure, byte[] userSecret,
            List<String> appDigestList, WatchlistReportDbHelper.AggregatedResult aggregatedResult) {
        if (DEBUG) Slog.i(TAG, "createDpEncodedReportMap start");
        final int appDigestListSize = appDigestList.size();
        final HashMap<String, Boolean> resultMap = new HashMap<>(appDigestListSize);
        for (int i = 0; i < appDigestListSize; i++) {
@@ -93,6 +96,7 @@ class PrivacyUtils {
                    ? createSecureDPEncoder(userSecret, appDigest)
                    : createInsecureDPEncoderForTest(appDigest);
            final boolean visitedWatchlist = aggregatedResult.appDigestList.contains(appDigest);
            if (DEBUG) Slog.i(TAG, appDigest + ": " + visitedWatchlist);
            // Get the least significant bit of first byte, and set result to True if it is 1
            boolean encodedVisitedWatchlist = ((int) encoder.encodeBoolean(visitedWatchlist)[0]
                    & 0x1) == 0x1;
+75 −31
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import java.io.File;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -61,6 +62,8 @@ class WatchlistLoggingHandler extends Handler {
    static final int LOG_WATCHLIST_EVENT_MSG = 1;
    @VisibleForTesting
    static final int REPORT_RECORDS_IF_NECESSARY_MSG = 2;
    @VisibleForTesting
    static final int FORCE_REPORT_RECORDS_NOW_FOR_TEST_MSG = 3;

    private static final long ONE_DAY_MS = TimeUnit.DAYS.toMillis(1);
    private static final String DROPBOX_TAG = "network_watchlist_report";
@@ -110,7 +113,15 @@ class WatchlistLoggingHandler extends Handler {
                break;
            }
            case REPORT_RECORDS_IF_NECESSARY_MSG:
                tryAggregateRecords();
                tryAggregateRecords(getLastMidnightTime());
                break;
            case FORCE_REPORT_RECORDS_NOW_FOR_TEST_MSG:
                if (msg.obj instanceof Long) {
                    long lastRecordTime = (Long) msg.obj;
                    tryAggregateRecords(lastRecordTime);
                } else {
                    Slog.e(TAG, "Msg.obj needs to be a Long object.");
                }
                break;
            default: {
                Slog.d(TAG, "WatchlistLoggingHandler received an unknown of message.");
@@ -146,6 +157,12 @@ class WatchlistLoggingHandler extends Handler {
        sendMessage(msg);
    }

    public void forceReportWatchlistForTest(long lastReportTime) {
        final Message msg = obtainMessage(FORCE_REPORT_RECORDS_NOW_FOR_TEST_MSG);
        msg.obj = lastReportTime;
        sendMessage(msg);
    }

    /**
     * Insert network traffic event to watchlist async queue processor.
     */
@@ -177,8 +194,14 @@ class WatchlistLoggingHandler extends Handler {
    }

    private boolean insertRecord(int uid, String cncHost, long timestamp) {
        if (DEBUG) {
            Slog.i(TAG, "trying to insert record with host: " + cncHost + ", uid: " + uid);
        }
        if (!mConfig.isConfigSecure() && !isPackageTestOnly(uid)) {
            // Skip package if config is not secure and package is not TestOnly app.
            if (DEBUG) {
                Slog.i(TAG, "uid: " + uid + " is not test only package");
            }
            return true;
        }
        final byte[] digest = getDigestFromUid(uid);
@@ -187,25 +210,25 @@ class WatchlistLoggingHandler extends Handler {
            return false;
        }
        final boolean result = mDbHelper.insertNewRecord(digest, cncHost, timestamp);
        tryAggregateRecords();
        return result;
    }

    private boolean shouldReportNetworkWatchlist() {
    private boolean shouldReportNetworkWatchlist(long lastRecordTime) {
        final long lastReportTime = Settings.Global.getLong(mResolver,
                Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME, 0L);
        final long currentTimestamp = System.currentTimeMillis();
        if (currentTimestamp < lastReportTime) {
        if (lastRecordTime < lastReportTime) {
            Slog.i(TAG, "Last report time is larger than current time, reset report");
            mDbHelper.cleanup();
            mDbHelper.cleanup(lastReportTime);
            return false;
        }
        return currentTimestamp >= lastReportTime + ONE_DAY_MS;
        return lastRecordTime >= lastReportTime + ONE_DAY_MS;
    }

    private void tryAggregateRecords() {
    private void tryAggregateRecords(long lastRecordTime) {
        long startTime = System.currentTimeMillis();
        try {
            // Check if it's necessary to generate watchlist report now.
        if (!shouldReportNetworkWatchlist()) {
            if (!shouldReportNetworkWatchlist(lastRecordTime)) {
                Slog.i(TAG, "No need to aggregate record yet.");
                return;
            }
@@ -213,9 +236,9 @@ class WatchlistLoggingHandler extends Handler {
            if (mDropBoxManager != null && mDropBoxManager.isTagEnabled(DROPBOX_TAG)) {
                Settings.Global.putLong(mResolver,
                        Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME,
                    System.currentTimeMillis());
                        lastRecordTime);
                final WatchlistReportDbHelper.AggregatedResult aggregatedResult =
                    mDbHelper.getAggregatedRecords();
                        mDbHelper.getAggregatedRecords(lastRecordTime);
                if (aggregatedResult == null) {
                    Slog.i(TAG, "Cannot get result from database");
                    return;
@@ -229,8 +252,14 @@ class WatchlistLoggingHandler extends Handler {
                if (encodedResult != null) {
                    addEncodedReportToDropBox(encodedResult);
                }
            } else {
                Slog.w(TAG, "Network Watchlist dropbox tag is not enabled");
            }
            mDbHelper.cleanup(lastRecordTime);
        } finally {
            long endTime = System.currentTimeMillis();
            Slog.i(TAG, "Milliseconds spent on tryAggregateRecords(): " + (endTime - startTime));
        }
        mDbHelper.cleanup();
    }

    /**
@@ -379,4 +408,19 @@ class WatchlistLoggingHandler extends Handler {
        }
        return subDomainList.toArray(new String[0]);
    }

    static long getLastMidnightTime() {
        return getMidnightTimestamp(0);
    }

    static long getMidnightTimestamp(int daysBefore) {
        java.util.Calendar date = new GregorianCalendar();
        // reset hour, minutes, seconds and millis
        date.set(java.util.Calendar.HOUR_OF_DAY, 0);
        date.set(java.util.Calendar.MINUTE, 0);
        date.set(java.util.Calendar.SECOND, 0);
        date.set(java.util.Calendar.MILLISECOND, 0);
        date.add(java.util.Calendar.DAY_OF_MONTH, -daysBefore);
        return date.getTimeInMillis();
    }
}
Loading