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

Commit e11325ab authored by Ricky Wai's avatar Ricky Wai Committed by android-build-merger
Browse files

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

am: b0558905

Change-Id: Ie8b2062a62c2d64b7b67646236ec048cb9afcf6d
parents e9761dcc b0558905
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