summaryrefslogtreecommitdiffhomepage
path: root/app/src/main/java/com/wireguard/android/util/SharedLibraryLoader.java
blob: e0bb579db3989683afe8856bdf897360a295ffd7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/*
 * Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

package com.wireguard.android.util;

import android.content.Context;
import android.os.Build;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public final class SharedLibraryLoader {
    private static final String TAG = "WireGuard/" + SharedLibraryLoader.class.getSimpleName();

    private SharedLibraryLoader() {
    }

    public static void loadSharedLibrary(final Context context, final String libName) {
        Throwable noAbiException;
        try {
            System.loadLibrary(libName);
            return;
        } catch (final UnsatisfiedLinkError e) {
            Log.d(TAG, "Failed to load library normally, so attempting to extract from apk", e);
            noAbiException = e;
        }

        final ZipFile zipFile;
        try {
            zipFile = new ZipFile(new File(context.getApplicationInfo().sourceDir), ZipFile.OPEN_READ);
        } catch (final IOException e) {
            throw new RuntimeException(e);
        }

        final String mappedLibName = System.mapLibraryName(libName);
        final byte[] buffer = new byte[1024 * 32];
        for (final String abi : Build.SUPPORTED_ABIS) {
            final String libZipPath = "lib" + File.separatorChar + abi + File.separatorChar + mappedLibName;
            final ZipEntry zipEntry = zipFile.getEntry(libZipPath);
            if (zipEntry == null)
                continue;
            File f = null;
            try {
                f = File.createTempFile("lib", ".so", context.getCacheDir());
                Log.d(TAG, "Extracting apk:/" + libZipPath + " to " + f.getAbsolutePath() + " and loading");
                try (final FileOutputStream out = new FileOutputStream(f);
                     final InputStream in = zipFile.getInputStream(zipEntry)) {
                    int len;
                    while ((len = in.read(buffer)) != -1) {
                        out.write(buffer, 0, len);
                    }
                }
                System.load(f.getAbsolutePath());
                return;
            } catch (final Exception e) {
                Log.d(TAG, "Failed to load library apk:/" + libZipPath, e);
                noAbiException = e;
            } finally {
                if (f != null)
                    // noinspection ResultOfMethodCallIgnored
                    f.delete();
            }
        }
        if (noAbiException instanceof RuntimeException)
            throw (RuntimeException) noAbiException;
        throw new RuntimeException(noAbiException);
    }
}