开发Android Studio VPN应用程序时出现错误消息

时间:2017-07-04 18:46:35

标签: android c++

在开发Open VPN应用程序时出现以下消息: 07-04 21:33:34.998 20337-21875 / pioneers.safwat.myvpn6 E / AndroidRuntime:致命异常:OpenVPNManagementThread                                                                         java.lang.UnsatisfiedLinkError:找不到本机方法:pioneers.safwat.myvpn6.NativeUtils.jniclose:(I)V                                                                             at pioneers.safwat.myvpn6.NativeUtils.jniclose(原生方法)                                                                             在pioneers.safwat.myvpn6.OpenVpnManagementThread.protectFileDescriptor(OpenVpnManagementThread.java:175)                                                                             在pioneers.safwat.myvpn6.OpenVpnManagementThread.processNeedCommand(OpenVpnManagementThread.java:387)                                                                             在pioneers.safwat.myvpn6.OpenVpnManagementThread.processCommand(OpenVpnManagementThread.java:227)                                                                             在pioneers.safwat.myvpn6.OpenVpnManagementThread.processInput(OpenVpnManagementThread.java:198)                                                                             在pioneers.safwat.myvpn6.OpenVpnManagementThread.run(OpenVpnManagementThread.java:146)                                                                             在java.lang.Thread.run(Thread.java:841) 07-04 21:33:35.288 20337-20337 / pioneers.safwat.myvpn6 E / ActivityThread:Activity pioneers.safwat.myvpn6.MainActivity_vpn已泄露最初绑定的ServiceConnection pioneers.safwat.myvpn6.MainActivity_vpn$1@42537e00                                                                         android.app.ServiceConnectionLeaked:Activity pioneers.safwat.myvpn6.MainActivity_vpn已泄露最初绑定的ServiceConnection pioneers.safwat.myvpn6.MainActivity_vpn$1@42537e00                                                                             在android.app.LoadedApk $ ServiceDispatcher。(LoadedApk.java:979)                                                                             在android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:873)                                                                             在android.app.ContextImpl.bindServiceAsUser(ContextImpl.java:1850)                                                                             在android.app.ContextImpl.bindService(ContextImpl.java:1838)                                                                             在android.content.ContextWrapper.bindService(ContextWrapper.java:503)                                                                             在pioneers.safwat.myvpn6.MainActivity_vpn.onCreate(MainActivity_vpn.java:53)                                                                             在android.app.Activity.performCreate(Activity.java:5372)                                                                             在android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1104)                                                                             在android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2270)

Nativeutilis类:

public class NativeUtils {
    public static native byte[] rsasign(byte[] input,int pkey) throws InvalidKeyException;
    public static native String[] getIfconfig() throws  IllegalArgumentException;
    static native void jniclose(int fdint);

    static {
    //  System.loadLibrary("opencv_java");
        System.loadLibrary("stlport_shared");
        System.loadLibrary("opvpnutil");
        System.loadLibrary("openvpn");
        System.loadLibrary("ssl");
        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN)
        System.loadLibrary("crypto");
    }
}

OpenVpnManagementThread类:

   public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {

    private static final String TAG = "Durai";
    private LocalSocket mSocket;
    private VpnProfile mProfile;
    private OpenVPNService mOpenVPNService;
    private LinkedList<FileDescriptor> mFDList = new LinkedList<FileDescriptor>();
    private LocalServerSocket mServerSocket;
    private boolean mReleaseHold = true;
    private boolean mWaitingForRelease = false;
    private long mLastHoldRelease = 0;

    private static final Vector<OpenVpnManagementThread> active = new Vector<OpenVpnManagementThread>();
    private LocalSocket mServerSocketLocal;

    private pauseReason lastPauseReason = pauseReason.noNetwork;

    public OpenVpnManagementThread(VpnProfile profile, OpenVPNService openVpnService) {
        mProfile = profile;
        mOpenVPNService = openVpnService;


        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(openVpnService);
        boolean managemeNetworkState = prefs.getBoolean("netchangereconnect", true);
        if (managemeNetworkState)
            mReleaseHold = false;

    }

    public boolean openManagementInterface(@NotNull Context c) {
        // Could take a while to open connection
        int tries = 8;

        String socketName = (c.getCacheDir().getAbsolutePath() + "/" + "mgmtsocket");
        // The mServerSocketLocal is transferred to the LocalServerSocket, ignore warning

        mServerSocketLocal = new LocalSocket();

        while (tries > 0 && !mServerSocketLocal.isConnected()) {
            try {
                mServerSocketLocal.bind(new LocalSocketAddress(socketName,
                        LocalSocketAddress.Namespace.FILESYSTEM));
            } catch (IOException e) {
                // wait 300 ms before retrying
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e1) {
                }

            }
            tries--;
        }

        try {

            mServerSocket = new LocalServerSocket(mServerSocketLocal.getFileDescriptor());
            return true;
        } catch (IOException e) {
            VpnStatus.logException(e);
        }
        return false;


    }

    public void managmentCommand(String cmd) {
        try {
            if (mSocket != null && mSocket.getOutputStream() != null) {
                mSocket.getOutputStream().write(cmd.getBytes());
                mSocket.getOutputStream().flush();
            }
        } catch (IOException e) {
            // Ignore socket stack traces
        }
    }


    @Override
    public void run() {
        byte[] buffer = new byte[2048];
        //  mSocket.setSoTimeout(5); // Setting a timeout cannot be that bad

        String pendingInput = "";
        synchronized (active) {
            active.add(this);
        }

        try {
            // Wait for a client to connect
            mSocket = mServerSocket.accept();
            InputStream instream = mSocket.getInputStream();
            // Close the management socket after client connected

            mServerSocket.close();
            // Closing one of the two sockets also closes the other
            //mServerSocketLocal.close();

            while (true) {
                int numbytesread = instream.read(buffer);
                if (numbytesread == -1)
                    return;

                FileDescriptor[] fds = null;
                try {
                    fds = mSocket.getAncillaryFileDescriptors();
                } catch (IOException e) {
                    VpnStatus.logException("Error reading fds from socket", e);
                }
                if (fds != null) {
                    Collections.addAll(mFDList, fds);
                }

                String input = new String(buffer, 0, numbytesread, "UTF-8");

                pendingInput += input;

                pendingInput = processInput(pendingInput);


            }
        } catch (IOException e) {
            if (!e.getMessage().equals("socket closed") && !e.getMessage().equals("Connection reset by peer"))
                VpnStatus.logException(e);
        }
        synchronized (active) {
            active.remove(this);
        }
    }

    //! Hack O Rama 2000!
    private void protectFileDescriptor(FileDescriptor fd) {
        Exception exp;
        try {
            Method getInt = FileDescriptor.class.getDeclaredMethod("getInt$");
            int fdint = (Integer) getInt.invoke(fd);
            boolean result = mOpenVPNService.protect(fdint);
            if (!result)
                VpnStatus.logWarning("Could not protect VPN socket");
            NativeUtils.jniclose(fdint);
            return;
        } catch (NoSuchMethodException e) {
            exp = e;
        } catch (IllegalArgumentException e) {
            exp = e;
        } catch (IllegalAccessException e) {
            exp = e;
        } catch (InvocationTargetException e) {
            exp = e;
        } catch (NullPointerException e) {
            exp = e;
        }

        Log.d("Openvpn", "Failed to retrieve fd from socket: " + fd);
        VpnStatus.logException("Failed to retrieve fd from socket (" + fd + ")", exp);
    }

    private String processInput(String pendingInput) {


        while (pendingInput.contains("\n")) {
            String[] tokens = pendingInput.split("\\r?\\n", 2);
            processCommand(tokens[0]);
            if (tokens.length == 1)
                // No second part, newline was at the end
                pendingInput = "";
            else
                pendingInput = tokens[1];
        }
        return pendingInput;
    }


    private void processCommand(String command) {
        //Log.i(TAG, "Line from managment" + command);


        if (command.startsWith(">") && command.contains(":")) {
            String[] parts = command.split(":", 2);
            String cmd = parts[0].substring(1);
            String argument = parts[1];


            if (cmd.equals("INFO")) {
                /* Ignore greeting from management */
                return;
            } else if (cmd.equals("PASSWORD")) {
                processPWCommand(argument);
            } else if (cmd.equals("HOLD")) {
                handleHold();
            } else if (cmd.equals("NEED-OK")) {
                processNeedCommand(argument);
            } else if (cmd.equals("BYTECOUNT")) {
                processByteCount(argument);
            } else if (cmd.equals("STATE")) {
                processState(argument);
            } else if (cmd.equals("PROXY")) {
                processProxyCMD(argument);
            } else if (cmd.equals("LOG")) {
                processLogMessage(argument);
            } else if (cmd.equals("RSA_SIGN")) {
                processSignCommand(argument);
            } else {
                VpnStatus.logWarning("MGMT: Got unrecognized command" + command);
                Log.i(TAG, "Got unrecognized command" + command);
            }
        } else if (command.startsWith("SUCCESS:")) {
            /* Ignore this kind of message too */
            return;
        } else if (command.startsWith("PROTECTFD: ")) {
            FileDescriptor fdtoprotect = mFDList.pollFirst();
            if (fdtoprotect != null)
                protectFileDescriptor(fdtoprotect);
        } else {
            Log.i(TAG, "Got unrecognized line from managment" + command);
            VpnStatus.logWarning("MGMT: Got unrecognized line from management:" + command);
        }
    }

    private void processLogMessage(String argument) {
        String[] args = argument.split(",", 4);
        Log.d("OpenVPN", argument);

        VpnStatus.LogLevel level;
        if (args[1].equals("I")) {
            level = VpnStatus.LogLevel.INFO;
        } else if (args[1].equals("W")) {
            level = VpnStatus.LogLevel.WARNING;
        } else if (args[1].equals("D")) {
            level = VpnStatus.LogLevel.VERBOSE;
        } else if (args[1].equals("F")) {
            level = VpnStatus.LogLevel.ERROR;
        } else {
            level = VpnStatus.LogLevel.INFO;
        }

        int ovpnlevel = Integer.parseInt(args[2]) & 0x0F;
        String msg = args[3];

        if (msg.startsWith("MANAGEMENT: CMD"))
            ovpnlevel = Math.max(4, ovpnlevel);

        VpnStatus.logMessageOpenVPN(level, ovpnlevel, msg);
    }

    private void handleHold() {
        if (mReleaseHold) {
            releaseHoldCmd();
        } else {
            mWaitingForRelease = true;
            VpnStatus.updateStatePause(lastPauseReason);

        }
    }

    private void releaseHoldCmd() {
        if ((System.currentTimeMillis() - mLastHoldRelease) < 5000) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException ignored) {
            }

        }
        mWaitingForRelease = false;
        mLastHoldRelease = System.currentTimeMillis();
        managmentCommand("hold release\n");
        managmentCommand("bytecount " + mBytecountInterval + "\n");
        managmentCommand("state on\n");
    }

    public void releaseHold() {
        mReleaseHold = true;
        if (mWaitingForRelease)
            releaseHoldCmd();

    }

    private void processProxyCMD(String argument) {
        String[] args = argument.split(",", 3);
        SocketAddress proxyaddr = ProxyDetection.detectProxy(mProfile);


        if (args.length >= 2) {
            String proto = args[1];
            if (proto.equals("UDP")) {
                proxyaddr = null;
            }
        }

        if (proxyaddr instanceof InetSocketAddress) {
            InetSocketAddress isa = (InetSocketAddress) proxyaddr;

            VpnStatus.logInfo(R.string.using_proxy, isa.getHostName(), isa.getPort());

            String proxycmd = String.format(Locale.ENGLISH, "proxy HTTP %s %d\n", isa.getHostName(), isa.getPort());
            managmentCommand(proxycmd);
        } else {
            managmentCommand("proxy NONE\n");
        }

    }

    private void processState(String argument) {
        String[] args = argument.split(",", 3);
        String currentstate = args[1];

        if (args[2].equals(",,"))
            VpnStatus.updateStateString(currentstate, "");
        else
            VpnStatus.updateStateString(currentstate, args[2]);
    }


    private void processByteCount(String argument) {
        //   >BYTECOUNT:{BYTES_IN},{BYTES_OUT}
        int comma = argument.indexOf(',');
        long in = Long.parseLong(argument.substring(0, comma));
        long out = Long.parseLong(argument.substring(comma + 1));
        VpnStatus.updateByteCount(in, out);
    }
    private void processNeedCommand(String argument) {
        int p1 = argument.indexOf('\'');
        int p2 = argument.indexOf('\'', p1 + 1);
        String needed = argument.substring(p1 + 1, p2);
        String extra = argument.split(":", 2)[1];
        String status = "ok";
        if (needed.equals("PROTECTFD")) {
            FileDescriptor fdtoprotect = mFDList.pollFirst();
            protectFileDescriptor(fdtoprotect);
        } else if (needed.equals("DNSSERVER")) {
            mOpenVPNService.addDNS(extra);
        } else if (needed.equals("DNSDOMAIN")) {
            mOpenVPNService.setDomain(extra);
        } else if (needed.equals("ROUTE")) {
            String[] routeparts = extra.split(" ");

            if (routeparts.length == 5) {
                if (BuildConfig.DEBUG) Assert.assertEquals("dev", routeparts[3]);
                mOpenVPNService.addRoute(routeparts[0], routeparts[1], routeparts[2], routeparts[4]);
            } else if (routeparts.length >= 3) {
                mOpenVPNService.addRoute(routeparts[0], routeparts[1], routeparts[2], null);
            } else {
                VpnStatus.logError("Unrecognized ROUTE cmd:" + Arrays.toString(routeparts) + " | " + argument);
            }

        } else if (needed.equals("ROUTE6")) {
            String[] routeparts = extra.split(" ");
            mOpenVPNService.addRoutev6(routeparts[0], routeparts[1]);
        } else if (needed.equals("IFCONFIG")) {
            String[] ifconfigparts = extra.split(" ");
            int mtu = Integer.parseInt(ifconfigparts[2]);
            mOpenVPNService.setLocalIP(ifconfigparts[0], ifconfigparts[1], mtu, ifconfigparts[3]);
        } else if (needed.equals("IFCONFIG6")) {
            mOpenVPNService.setLocalIPv6(extra);

        } else if (needed.equals("PERSIST_TUN_ACTION")) {
            // check if tun cfg stayed the same
            status = mOpenVPNService.getTunReopenStatus();
        } else if (needed.equals("OPENTUN")) {
            if (sendTunFD(needed, extra))
                return;
            else
                status = "cancel";
        } else {
            Log.e(TAG, "Unkown needok command " + argument);
            return;
        }
        String cmd = String.format("needok '%s' %s\n", needed, status);
        managmentCommand(cmd);
    }
    private boolean sendTunFD(String needed, String extra) {
        Exception exp;
        if (!extra.equals("tun")) {
            VpnStatus.logError(String.format("Device type %s requested, but only tun is possible with the Android API, sorry!", extra));
            return false;
        }
        ParcelFileDescriptor pfd = mOpenVPNService.openTun();
        if (pfd == null)
            return false;

        Method setInt;
        int fdint = pfd.getFd();
        try {
            setInt = FileDescriptor.class.getDeclaredMethod("setInt$", int.class);
            FileDescriptor fdtosend = new FileDescriptor();
            setInt.invoke(fdtosend, fdint);
            FileDescriptor[] fds = {fdtosend};
            mSocket.setFileDescriptorsForSend(fds);
            String cmd = String.format("needok '%s' %s\n", needed, "ok");
            managmentCommand(cmd);
            mSocket.setFileDescriptorsForSend(null);
            pfd.close();
            return true;
        } catch (NoSuchMethodException e) {
            exp = e;
        } catch (IllegalArgumentException e) {
            exp = e;
        } catch (IllegalAccessException e) {
            exp = e;
        } catch (InvocationTargetException e) {
            exp = e;
        } catch (IOException e) {
            exp = e;
        }
        VpnStatus.logException("Could not send fd over socket", exp);
        return false;
    }

    private void processPWCommand(String argument) {
        String needed;
        try {

            int p1 = argument.indexOf('\'');
            int p2 = argument.indexOf('\'', p1 + 1);
            needed = argument.substring(p1 + 1, p2);
            if (argument.startsWith("Verification Failed")) {
                proccessPWFailed(needed, argument.substring(p2 + 1));
                return;
            }
        } catch (StringIndexOutOfBoundsException sioob) {
            VpnStatus.logError("Could not parse management Password command: " + argument);
            return;
        }
        String pw = null;

        if (needed.equals("Private Key")) {
            pw = mProfile.getPasswordPrivateKey();
        } else if (needed.equals("Auth")) {
            String usercmd = String.format("username '%s' %s\n",
                    needed, VpnProfile.openVpnEscape(mProfile.mUsername));
            managmentCommand(usercmd);
            pw = mProfile.getPasswordAuth();
        }
        if (pw != null) {
            String cmd = String.format("password '%s' %s\n", needed, VpnProfile.openVpnEscape(pw));
            managmentCommand(cmd);
        } else {
            VpnStatus.logError(String.format("Openvpn requires Authentication type '%s' but no password/key information available", needed));
        }
    }

    private void proccessPWFailed(String needed, String args) {
        VpnStatus.updateStateString("AUTH_FAILED", needed + args,R.string.state_auth_failed, VpnStatus.ConnectionStatus.LEVEL_AUTH_FAILED);
    }
    private static boolean stopOpenVPN() {
        synchronized (active) {
            boolean sendCMD = false;
            for (OpenVpnManagementThread mt : active) {
                mt.managmentCommand("signal SIGINT\n");
                sendCMD = true;
                try {
                    if (mt.mSocket != null)
                        mt.mSocket.close();
                } catch (IOException e) {
                }
            }
            return sendCMD;
        }
    }

    @Override
    public void networkChange() {
        if (!mWaitingForRelease)
            managmentCommand("network-change\n");
    }

    public void signalusr1() {
        mReleaseHold = false;

        if (!mWaitingForRelease)
            managmentCommand("signal SIGUSR1\n");
        else
            VpnStatus.updateStatePause(lastPauseReason);
    }

    public void reconnect() {
        signalusr1();
        releaseHold();
    }
    private void processSignCommand(String b64data) {
        String signed_string = mProfile.getSignedData(b64data);
        if (signed_string == null) {
            managmentCommand("rsa-sig\n");
            managmentCommand("\nEND\n");
            stopOpenVPN();
            return;
        }
        managmentCommand("rsa-sig\n");
        managmentCommand(signed_string);
        managmentCommand("\nEND\n");
    }
    @Override
    public void pause(pauseReason reason) {
        lastPauseReason = reason;
        signalusr1();
    }

    @Override
    public void resume() {
        releaseHold();
        /* Reset the reason why we are disconnected */
        lastPauseReason = pauseReason.noNetwork;
    }
    @Override
    public boolean stopVPN() {
        return stopOpenVPN();
    }
}

MainActivity_vpn类:

public class MainActivity_vpn extends Activity {
protected OpenVPNService mService;
boolean mBound = false;
private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName className,
                                   IBinder service) {
        OpenVPNService.LocalBinder binder = (OpenVPNService.LocalBinder) service;
        mService = binder.getService();
        mBound = true;
    }
    @Override
    public void onServiceDisconnected(ComponentName arg0) {
        mService =null;
        mBound = false;
    }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main_vpn);
    Intent intent = new Intent(getBaseContext(), OpenVPNService.class);
    intent.setAction(OpenVPNService.START_SERVICE);
    bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    registerReceiver(broadcastReceiver, new IntentFilter("CONNECTION_CHANGE"));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);

    getMenuInflater().inflate(R.menu.settingsmenu, menu);
    return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    if (Constants.isVPNConnected){
        // disable connect button if VPN is connected
        menu.getItem(0).setEnabled(false);
        // enable disconnect button if VPN is connected
        menu.getItem(1).setEnabled(true);
    } else{
        // enable connect button if VPN is disconnected
        menu.getItem(0).setEnabled(true);
        // disable disconnect button if VPN is disconnected
        menu.getItem(1).setEnabled(false);
    }
    return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {

    switch (item.getItemId()) {
        case R.id.action_startvpn:
            configureAndStartVpn() ;
            return true ;
        case R.id.action_stopvpn:
            stopVPN() ;
            return true ;
        case R.id.action_removeProfile:
            removeProfile();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}
private void removeProfile() {

    final ProfileManager pm = ProfileManager.getInstance(MainActivity_vpn.this) ;
    final VpnProfile profile = pm.getProfileByName(Constants.VPN_PROFILE_NAME) ;

    if (profile != null) {
                        stopVPN() ;
                        pm.removeProfile(getApplicationContext(),profile);
                        int duration = Toast.LENGTH_SHORT;
                        Toast toast = Toast.makeText(MainActivity_vpn.this,"The VPN Configuration is deleted", duration);
                        toast.show();
    } else {
                int duration = Toast.LENGTH_LONG;
        Toast toast = Toast.makeText(MainActivity_vpn.this,"There are no VPN Configurations to delete", duration);toast.show();
    }
}
private void stopVPN() {
    try{
        ProfileManager.setConntectedVpnProfileDisconnected(MainActivity_vpn.this);
        if(mService.getManagement()!=null)
            mService.getManagement().stopVPN();
    }
    catch (Exception ex){
    }
}
private void configureAndStartVpn() {
    try {
                EditText Et_Ovpn = (EditText) findViewById(R.id.et_ovpn);

                String retVal = Et_Ovpn.getText().toString();

                if (retVal != null && retVal.trim().length()>0) {

                    byte[] buffer = retVal.getBytes() ;

                    VpnProfile vp = saveProfile(buffer) ;

                    if (vp != null) {
                        startVPN(vp) ;
                    }
                }
                else {
                    int duration = Toast.LENGTH_LONG;
                    Toast toast = Toast.makeText(MainActivity_vpn.this,"Connecting using the last vpn configuration", duration);
                    toast.show();
                    startVPN();
                }
    } catch (Exception e) {
        e.printStackTrace() ;
    }
}
private VpnProfile saveProfile(byte [] data) {

    ConfigParser cp = new ConfigParser();
    try {
        InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(data));
        cp.parseConfig(isr);
        VpnProfile vp = cp.convertProfile();
        ProfileManager vpl = ProfileManager.getInstance(this);
        vp.mName = Constants.VPN_PROFILE_NAME ;
        vpl.addProfile(vp);
        vpl.saveProfile(this, vp);
        vpl.saveProfileList(this);
        return vp ;
    } catch(Exception e) {
        return null ;
    }
}
public void startVPN(VpnProfile vp) {
    Intent intent = new Intent(getApplicationContext(),LaunchVPN.class);
    intent.putExtra(LaunchVPN.EXTRA_KEY, vp.getUUID().toString());
    intent.setAction(Intent.ACTION_MAIN);
    startActivity(intent);
}
private void startVPN() {

    ProfileManager pm = ProfileManager.getInstance(this) ;
    VpnProfile profile = pm.getProfileByName(Constants.VPN_PROFILE_NAME) ;

    if (profile == null) {
        int duration = Toast.LENGTH_LONG;
        Toast toast = Toast.makeText(MainActivity_vpn.this,"There are no VPN Configurations.So paste the .OVPN and try", duration);
        toast.show();
        return ;
    }

    Intent intent = new Intent(this,LaunchVPN.class);
    intent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString());
    intent.setAction(Intent.ACTION_MAIN);
    startActivity(intent);
}
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        stopVPN();
        startVPN();
    }
};

@Override
protected void onDestroy() {
    super.onDestroy();
    unregisterReceiver(broadcastReceiver);
}

}

3 个答案:

答案 0 :(得分:0)

从日志中我看到了这一行:

MainActivity_vpn has leaked ServiceConnection

在您的活动OnCreate中,您对服务具有约束力,但您永远不会解除绑定。 在onDestroy

中将此添加到MainActivity方法中
    if (mServiceConn != null) {
      unbindService(mServiceConn);
    }

另外,请看: JNI- java.lang.UnsatisfiedLinkError: Native method not found

我认为您应该从方法签名中删除静态

答案 1 :(得分:0)

我没有考虑到本机方法的声明应该放在与捐赠项目中具有相同名称和包的类中。 一旦我更改了本机方法的包名称,问题就解决了

答案 2 :(得分:0)

private VpnProfile saveProfile(byte [] data) {

ConfigParser cp = new ConfigParser();
try {
    InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(data));
    cp.parseConfig(isr);

这里ConfigParser()不是公共类,因此您可以创建它的实例。

This is from the android SDK 29