1. 程式人生 > >Android 8.1移植:針對某個APK做到wifi和gprs分別做到允許和禁止兩種策略

Android 8.1移植:針對某個APK做到wifi和gprs分別做到允許和禁止兩種策略

在MTK平臺JB5開始後預設有該功能,昨天在檢視8.1的程式碼時發現沒有該功能,現在我把移植流程記錄下來,親測驗證ok。

1.frameworks
frameworks/base/core/java/android/os/INetworkManagementService.aidl

void setFirewallUidChainRule(int uid, int networkType, boolean allow); //zrx add
void clearFirewallChain(String chain);   //zrx add

frameworks/base/services/core/java/com/android/server/NetworkManagementService.java

 //add by zrx

    /**
     * @hide
     * @param uid
     * @param networkType
     * @param allow
     */
    public void setFirewallUidChainRule(int uid, int networkType, boolean allow) {
        //enforceSystemUid();
        final String MOBILE = "mobile";
        final String WIFI = "wifi";

        final
String rule = allow ? "allow" : "deny"; final String chain = (networkType == 1) ? WIFI : MOBILE; try { mConnector.execute("firewall", "set_uid_fw_rule", uid, chain, rule); } catch (NativeDaemonConnectorException e) { throw e.rethrowAsParcelableException(); } } /** * @internal
Configure firewall rule by uid and chain * @hide */
public void clearFirewallChain(String chain) { //enforceSystemUid(); try { mConnector.execute("firewall", "clear_fw_chain", chain); } catch (NativeDaemonConnectorException e) { throw e.rethrowAsParcelableException(); } } //add by zrx

上面兩個函式是提供給上層呼叫的,setFirewallUidChainRule和clearFirewallChain為設定和清空相應的APP的限制

2.system/netd/server/路徑
CommandListener.cpp

int CommandListener::FirewallCmd::runCommand(SocketClient *cli, int argc,char **argv) { 
//add  by zrx 在cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);之前加上
      if (!strcmp(argv[1], "set_uid_fw_rule")) {
        if (argc != 5) {
            cli->sendMsg(ResponseCode::CommandSyntaxError,
                         "Usage: firewall set_uid_fw_rule <uid> <mobile|wifi> <allow|deny>",
                         false);
            return 0;
        }

        int uid = atoi(argv[2]);
        FirewallChinaRule chain = parseChain(argv[3]);
        FirewallRule rule = parseRule(argv[4]);

        int res = gCtls->firewallCtrl.setUidFwRule(uid, chain, rule);
        return sendGenericOkFail(cli, res);
    }

    if (!strcmp(argv[1], "clear_fw_chain")) {
        if (argc != 3) {
            cli->sendMsg(ResponseCode::CommandSyntaxError,
                         "Usage: firewall clear_fw_chain <chain>",
                         false);
            return 0;
        }

        const char* chain = argv[2];

        int res = gCtls->firewallCtrl.clearFwChain(chain);
        return sendGenericOkFail(cli, res);
    }   
    //add  by zrx

    cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);
    return 0;
}

FirewallChinaRule CommandListener::FirewallCmd::parseChain(const char* arg) {
    if (!strcmp(arg, "mobile")) {
            return MOBILE;
    } else {
            return WIFI;
    }
}

CommandListener.h宣告parseChain函式

    int sendGenericOkFail(SocketClient *cli, int cond);
        static FirewallRule parseRule(const char* arg);
        static FirewallType parseFirewallType(const char* arg);
        static ChildChain parseChildChain(const char* arg);
        // zrx add: Support enhanced firewall @{
        static FirewallChinaRule parseChain(const char* arg);

FirewallController.cpp對setUidFwRule和clearFwChain函式新增

// zrx add Support tencent firewall @{
const char* FirewallController::FIREWALL = "firewall";
const char* FirewallController::FIREWALL_MOBILE = "mobile";
const char* FirewallController::FIREWALL_WIFI = "wifi";
//@}

/****************************************************************************
* zrx add: support tencent firewall
* set FIREWALL_MOBILE and FIREWALL_WIFI rule to reject packets based on uid
*****************************************************************************/
int FirewallController::setUidFwRule(int uid, FirewallChinaRule chain, FirewallRule rule) {
    char uidStr[16];
    int res = 0;
    const char* op;
    const char* fwChain;

    sprintf(uidStr, "%d", uid);

    if (rule == ALLOW) {
        op = "-I";
    } else {
        op = "-D";
    }

    if(chain == MOBILE) {
        fwChain = "mobile";
    }else{
        fwChain = "wifi";
    }
 //在8.1上用execIptablesRestore函式,但因為我對C++語言不精通,我就把6.0上的execIptables函式移植過來了。
    res |= execIptables(V4, op, fwChain, "-m", "owner", "--uid-owner", uidStr,
            "-j", "REJECT", "--reject-with", "icmp-net-prohibited", NULL);
    res |= execIptables(V6, op, fwChain, "-m", "owner", "--uid-owner", uidStr,
            "-j", "REJECT", "--reject-with", "icmp6-adm-prohibited", NULL);

    return res;
}


/************************************************************
* zrx add: support tencent firewall
* flush FIREWALL_MOBILE and FIREWALL_WIFI
************************************************************/
int FirewallController::clearFwChain(const char* chain) {
    int res = 0;

    if(chain != NULL){
        if(strlen(chain) > 0){
            res |= execIptables(V4V6, "-F", chain, NULL);
        }else{
            ALOGD("Clear all chain");
            res |= execIptables(V4V6, "-F", NULL);
        }
    }else{
        ALOGE("Chain is NULL");
    }

    return res;
}

int FirewallController::setupIptablesHooks(void) {
     // zrx add: Support enhanced firewall @{
    int res = 0;
    res |= execIptables(V4V6, "-F", FIREWALL, NULL);
    res |= execIptables(V4V6, "-A", FIREWALL, "-o", "ppp+", "-j", FIREWALL_MOBILE, NULL);
    res |= execIptables(V4V6, "-A", FIREWALL, "-o", "ccmni+", "-j", FIREWALL_MOBILE, NULL);
    res |= execIptables(V4V6, "-A", FIREWALL, "-o", "ccemni+", "-j", FIREWALL_MOBILE, NULL);
    res |= execIptables(V4V6, "-A", FIREWALL, "-o", "usb+", "-j", FIREWALL_MOBILE, NULL);
    res |= execIptables(V4V6, "-A", FIREWALL, "-o", "cc2mni+", "-j", FIREWALL_MOBILE, NULL);
    res |= execIptables(V4V6, "-A", FIREWALL, "-o", "wlan+", "-j", FIREWALL_WIFI, NULL);
    //@}
    res |= createChain(LOCAL_DOZABLE, getFirewallType(DOZABLE));
    res |= createChain(LOCAL_STANDBY, getFirewallType(STANDBY));
    res |= createChain(LOCAL_POWERSAVE, getFirewallType(POWERSAVE));
    return res;
}

FirewallController.h

enum FirewallChinaRule { MOBILE, WIFI };//zrx add

public:
    FirewallController();
    int setupIptablesHooks(void);
    int enableFirewall(FirewallType);
    int disableFirewall(void);
    int isFirewallEnabled(void);
    // zrx add, Support enhanced firewall @{
    static const char* FIREWALL;
    static const char* FIREWALL_MOBILE;
    static const char* FIREWALL_WIFI;
    int setUidFwRule(int, FirewallChinaRule, FirewallRule);
    int clearFwChain(const char* chain);
    //@}
    //add  by zrx

NetdConstants.cpp實現execIptables函式

//zrx add
const char * const IPTABLES_PATH = "/system/bin/iptables";
const char * const IP6TABLES_PATH = "/system/bin/ip6tables";
static void logExecError(const char* argv[], int res, int status) {
    const char** argp = argv;
    std::string args = "";
    while (*argp) {
        args += *argp;
        args += ' ';
        argp++;
    }
    ALOGE("exec() res=%d, status=%d for %s", res, status, args.c_str());
}

static int execIptablesCommand(int argc, const char *argv[], bool silent) {
    int res;
    int status;

    ALOGI("execIptablesCommand android_fork_execvp enter");
    res = android_fork_execvp(argc, (char **)argv, &status, false,
        !silent);
    ALOGI("execIptablesCommand android_fork_execvp exit");
    if (res || !WIFEXITED(status) || WEXITSTATUS(status)) {
        if (!silent) {
            logExecError(argv, res, status);
        }
        if (res)
            return res;
        if (!WIFEXITED(status))
            return ECHILD;
    }
    return WEXITSTATUS(status);
}

static int execIptables(IptablesTarget target, bool silent, va_list args) {
    /* Read arguments from incoming va_list; we expect the list to be NULL terminated. */
    std::list<const char*> argsList;
    argsList.push_back(NULL);
    const char* arg;

    // Wait to avoid failure due to another process holding the lock
    argsList.push_back("-w");

    do {
        arg = va_arg(args, const char *);
        argsList.push_back(arg);
    } while (arg);

    int i = 0;
    const char* argv[argsList.size()];
    std::list<const char*>::iterator it;
    for (it = argsList.begin(); it != argsList.end(); it++, i++) {
        argv[i] = *it;
    }

    int res = 0;
    if (target == V4 || target == V4V6) {
        argv[0] = IPTABLES_PATH;
        res |= execIptablesCommand(argsList.size(), argv, silent);
    }
    if (target == V6 || target == V4V6) {
        argv[0] = IP6TABLES_PATH;
        res |= execIptablesCommand(argsList.size(), argv, silent);
    }
    return res;
}

int execIptables(IptablesTarget target, ...) {
    va_list args;
    va_start(args, target);
    int res = execIptables(target, false, args);
    va_end(args);
    return res;
}

int execIptablesSilently(IptablesTarget target, ...) {
    va_list args;
    va_start(args, target);
    int res = execIptables(target, true, args);
    va_end(args);
    return res;
}
//zrx add

NetdConstants.h

int execIptables(IptablesTarget target, ...); //zrx add
int execIptablesSilently(IptablesTarget target, ...);//zrx add

Controllers.cpp

static const std::vector<const char*> FILTER_INPUT = {
        // Bandwidth should always be early in input chain, to make sure we
        // correctly count incoming traffic against data plan.
        BandwidthController::LOCAL_INPUT,
        // zrx add: Support enhanced firewall @{
        FirewallController::FIREWALL,
        ///@}
        FirewallController::LOCAL_INPUT,
};

static const std::vector<const char*> FILTER_OUTPUT = {
        OEM_IPTABLES_FILTER_OUTPUT,
        // zrx add: Support enhanced firewall @{
        FirewallController::FIREWALL,
        ///@}
        FirewallController::LOCAL_OUTPUT,
        StrictController::LOCAL_OUTPUT,
        BandwidthController::LOCAL_OUTPUT,
};

// zrx add:  @{
static const std::vector<const char*> FILTER_FIREWALL = {
        FirewallController::FIREWALL_MOBILE,
        FirewallController::FIREWALL_WIFI,
        NULL,
};///@}

void Controllers::initChildChains() {
    /*
     * This is the only time we touch top-level chains in iptables; controllers
     * should only mutate rules inside of their children chains, as created by
     * the constants above.
     *
     * Modules should never ACCEPT packets (except in well-justified cases);
     * they should instead defer to any remaining modules using RETURN, or
     * otherwise DROP/REJECT.
     */

    // Create chains for child modules.
    createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT, true);
    // zrx add:  @{
    createChildChains(V4V6, "filter", "firewall", FILTER_FIREWALL,true); 
    ///@}
    createChildChains(V4V6, "filter", "FORWARD", FILTER_FORWARD, true);
    createChildChains(V4V6, "raw", "PREROUTING", RAW_PREROUTING, true);
    createChildChains(V4V6, "mangle", "FORWARD", MANGLE_FORWARD, true);
    createChildChains(V4V6, "mangle", "INPUT", MANGLE_INPUT, true);
    createChildChains(V4, "nat", "PREROUTING", NAT_PREROUTING, true);
    createChildChains(V4, "nat", "POSTROUTING", NAT_POSTROUTING, true);

    createChildChains(V4, "filter", "OUTPUT", FILTER_OUTPUT, false);
    createChildChains(V6, "filter", "OUTPUT", FILTER_OUTPUT, false);
    createChildChains(V4, "mangle", "POSTROUTING", MANGLE_POSTROUTING, false);
    createChildChains(V6, "mangle", "POSTROUTING", MANGLE_POSTROUTING, false);
}

4.上層app驗證

import android.os.INetworkManagementService;
import android.os.ServiceManager;

private INetworkManagementService mNetworkService;
mNetworkService = INetworkManagementService.Stub.asInterface(
                    ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
//允許系統瀏覽器上網功能
try {
       mNetworkService.setFirewallUidChainRule(10057,1, false);//uid通過eng版本cat /data/system/packages.xml獲得,1為允許wifi,2或者其他數字代表gprs,false為不禁止,true為允許禁止
       mNetworkService.setFirewallUidChainRule(10057,2, false);
    } catch (Exception e) {
        // TODO: handle exception
        e.printStackTrace();
    }

//禁止系統瀏覽器上網功能
 mNetworkService.setFirewallUidChainRule(10057,1, true);
       mNetworkService.setFirewallUidChainRule(10057,2, true);
    } catch (Exception e) {
        // TODO: handle exception
        e.printStackTrace();
    }

最後還需要在AndroidManifest.xml中加上android:sharedUserId=”android.uid.system”這個屬性。