您的位置:首页 > 理论基础 > 计算机网络

Android应用网络限制功能实现

2017-09-19 20:39 267 查看
  在之前的博文Android防火墙功能实现与原理分析中分析了Android防火墙实现原理,这里继续讲解Android 应用网络限制实现流程。

  

  先看看需求:现在4G流量费用比较昂贵,为了避免流量的消耗,我们可以限制某个应用连接网络,或者限制某个app只能使用wifi等等。

  

  再看看效果图:

            


  当我们使用流量上网时,会发现此时谷歌浏览器无法连接网络,这就达到了我们的目的。

  不多说,直接上代码。

  1.第一步:我们需要把我们控制网络的方法声明在frameworks/base/core/Java/android/os/INetworkManagementService.aidl中:

interface INetworkManagementService
{
……
void setMobileDataUidRule(int uid, boolean allow);

void setWifiDataUidRule(int uid, boolean allow);
……
}


  第二步:在frameworks/base/services/core/java/com/android/server目录下的NetworkManagementService.java中实现我们声明的两个方法:

//add by xiaoxsen
public void setMobileDataUidRule(int uid, boolean allow) {
enforceSystemUid();//check
try {
final String rule = allow ? "allow" : "deny";
mConnector.execute("firewall", "set_mobile_data_uid_rule", uid, rule);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}

public void setWifiDataUidRule(int uid, boolean allow) {
enforceSystemUid();
try {
final String rule = allow ? "allow" : "deny";
mConnector.execute("firewall", "set_wifi_data_uid_rule", uid, rule);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
//add by xiaoxsen


  第三步:下面又通过socket通信方式调用到system/netd层的system/netd/server目录下的CommandListener.cpp中添加如下:

CommandListener::CommandListener() :
FrameworkListener("netd", true) {
//add  by xiaoxsen
sFirewallCtrl->initIptableFirewall();// 开机初始化
//add  by xiaoxsen
.......
}


  然后在int CommandListener::FirewallCmd::runCommand()中添加:

//add  by xiaoxsen
if (!strcmp(argv[1], "set_mobile_data_uid_rule")) {
if (argc != 4) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage: firewall set_mobile_data_uid_rule <1000> <allow|deny>",
false);
return 0;
}
int uid = atoi(argv[2]);
FirewallRule rule = parseRule(argv[3]);
int res = sFirewallCtrl->setMobileDataUidRule(uid, rule);
return sendGenericOkFail(cli, res);
}
if (!strcmp(argv[1], "set_wifi_data_uid_rule")) {
if (argc != 4) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage: firewall set_wifi_data_uid_rule <1000> <allow|deny>",
false);
return 0;
}
int uid = atoi(argv[2]);
FirewallRule rule = parseRule(argv[3]);
int res = sFirewallCtrl->setWifiDataUidRule(uid, rule);
return sendGenericOkFail(cli, res);
}
//add  by xiaoxsen


  上面代码又调用到system/netd/server目录下的FirewallController.cpp的方法,添加的方法如下:

#include <cutils/properties.h>
//add  by xiaoxsen
const char* op_3g;
const char* op_wifi;
. . .
int FirewallController::initIptableFirewall(void) {
int res = 0;
op_3g = "ccmni+"; //网络端口
op_wifi = "wlan0";//wifi网络端口
//查看网络端口的方法:
//1.输入adb shell
//2.输入netcfg

// 新建一个drop_wall链表
res |= execIptables(V4V6, "-w", "-N", "drop_wall", NULL);
// 把新建的drop_wall链表添加到OUTPUT链表目录下
res |= execIptables(V4V6, "-w", "-A", "OUTPUT", "-j", "drop_wall", NULL);
}
int FirewallController::setMobileDataUidRule(int uid, FirewallRule rule) {
char uidStr[16];
sprintf(uidStr, "%d", uid);
const char* op;
if (rule == ALLOW) {
op = "-D";// 删除链表中的规则
} else {
op = "-A";// 添加规则到链表
}
int res = 0;
res |= execIptables(V4V6, "-w", op, "drop_wall", "-o", op_3g, "-m", "owner",
"--uid-owner", uidStr, "-j", "REJECT", NULL);
return res;
}

int FirewallController::setWifiDataUidRule(int uid, FirewallRule rule) {
char uidStr[16];
sprintf(uidStr, "%d", uid);
const char* op;
if (rule == ALLOW) {
op = "-D";// 删除链表中的规则
} else {
op = "-A";// 添加规则到链表
}
int res = 0;
res |= execIptables(V4V6, "-w", op, "drop_wall", "-o", op_wifi, "-m", "owner",
"--uid-owner", uidStr, "-j", "REJECT", NULL);
return res;
}
//add  by xiaoxsen


   上面添加的方法声明在system/netd/server目录下的FirewallController.h中:

class FirewallController {
public:
. . .
//add  by xiaoxsen
int initIptableFirewall(void);
int setMobileDataUidRule(int, FirewallRule);
int setWifiDataUidRule(int, FirewallRule);
//add  by xiaoxsen
. . .
}


  第四步:调用方法实现防火墙功能:

networkManagementService = INetworkManagementService.
Stub.asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
if (networkManagementService != null) {
networkManagementService. setMobileDataUidRule (10038,true);
networkManagementService. setWifiDataUidRule (10048, true);
}


这里只要传递应用的uid进去就可以实现。

获取uid的方式:

List<AppdataInfo> installApplictionList = new ArrayList<AppdataInfo>();
pm = mContext.getPackageManager();
List<ApplicationInfo> installedApplications = pm.getInstalledApplications(PackageManager.GET_META_DATA);
for (ApplicationInfo applicationInfo : installedApplications) {

if (applicationInfo != null && PackageManager.PERMISSION_GRANTED == pm
.checkPermission(Manifest.permission.INTERNET,
applicationInfo.packageName)) {
//这样就能获取到有网络权限应用的uid
int uid = applicationInfo.uid

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: