aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/app/src/main/java/com/wireguard/android/util/SharedLibraryLoader.java
blob: f3816939117c42785e21318911558df1524386a0 (plain) (blame)
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
76
77
78
79
80
81
82
83
84
85
86
/*
 * Copyright © 2017-2019 WireGuard LLC. 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.Arrays;
import java.util.Collection;
import java.util.HashSet;
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 Collection<String> apks = new HashSet<>();
        if (context.getApplicationInfo().sourceDir != null)
            apks.add(context.getApplicationInfo().sourceDir);
        if (context.getApplicationInfo().splitSourceDirs != null)
            apks.addAll(Arrays.asList(context.getApplicationInfo().splitSourceDirs));

        for (final String apk : apks) {
            final ZipFile zipFile;
            try {
                zipFile = new ZipFile(new File(apk), 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);
    }
}