Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
QtApkFileEngine.java
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:file-handling
4
5package org.qtproject.qt.android;
6
7import android.content.Context;
8import android.content.res.AssetFileDescriptor;
9import android.content.res.AssetManager;
10import android.os.Build;
11import android.content.pm.ApplicationInfo;
12import android.content.pm.PackageManager;
13
14import java.io.FileInputStream;
15import java.io.ByteArrayOutputStream;
16import java.io.IOException;
17
18import java.util.zip.ZipFile;
19import java.util.Enumeration;
20import java.util.zip.ZipEntry;
21import java.util.ArrayList;
22import java.util.Arrays;
23import java.util.HashSet;
24import java.util.Comparator;
25
26import android.util.Log;
27
28import java.nio.channels.FileChannel;
29import java.nio.channels.FileChannel.MapMode;
30import java.nio.MappedByteBuffer;
31import java.nio.ByteOrder;
32
34class QtApkFileEngine {
35 private final static String QtTAG = QtApkFileEngine.class.getSimpleName();
36 private static String m_appApkPath;
37
38 private AssetFileDescriptor m_assetFd;
39 private final AssetManager m_assetManager;
40 private FileInputStream m_assetInputStream;
41 private long m_pos = -1;
42
43 QtApkFileEngine(Context context)
44 {
45 m_assetManager = context.getAssets();
46 }
47
48 boolean open(String fileName)
49 {
50 try {
51 m_assetFd = m_assetManager.openNonAssetFd(fileName);
52 m_assetInputStream = m_assetFd.createInputStream();
53 } catch (IOException e) {
54 Log.e(QtTAG, "Failed to open the app APK with " + e);
55 }
56
57 return m_assetInputStream != null;
58 }
59
60 boolean close()
61 {
62 try {
63 if (m_assetInputStream != null)
64 m_assetInputStream.close();
65 if (m_assetFd != null)
66 m_assetFd.close();
67 } catch (IOException e) {
68 Log.e(QtTAG, "Failed to close resources with " + e);
69 }
70
71 return m_assetInputStream == null && m_assetFd == null;
72 }
73
74 long pos()
75 {
76 return m_pos;
77 }
78
79 boolean seek(int pos)
80 {
81 if (m_assetInputStream != null && m_assetInputStream.markSupported()) {
82 try {
83 m_assetInputStream.mark(pos);
84 m_assetInputStream.reset();
85 m_pos = pos;
86 return true;
87 } catch (IOException ignored) { }
88 }
89
90 return false;
91 }
92
93 MappedByteBuffer getMappedByteBuffer(long offset, long size)
94 {
95 try {
96 FileChannel fileChannel = m_assetInputStream.getChannel();
97 long position = fileChannel.position() + offset;
98 MappedByteBuffer mapped = fileChannel.map(MapMode.READ_ONLY, position, size);
99 mapped.order(ByteOrder.LITTLE_ENDIAN);
100 fileChannel.close();
101
102 return mapped;
103 } catch (Exception e) {
104 Log.e(QtTAG, "Failed to map APK file to memory with " + e);
105 }
106
107 return null;
108 }
109
110 byte[] read(long maxlen)
111 {
112 if (m_assetInputStream == null)
113 return null;
114
115 int bytesRead;
116 int totalBytesRead = 0;
117 byte[] buffer = new byte[1024];
118 try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
119 while (totalBytesRead < maxlen) {
120 int remainingBytes = (int) maxlen - totalBytesRead;
121 int bytesToRead = Math.min(buffer.length, remainingBytes);
122 if ((bytesRead = m_assetInputStream.read(buffer, 0, bytesToRead)) == -1)
123 break;
124 outputStream.write(buffer, 0, bytesRead);
125 totalBytesRead += bytesRead;
126 }
127 return outputStream.toByteArray();
128 } catch (IOException e) {
129 Log.e(QtTAG, "Failed to read content with " + e);
130 }
131
132 return null;
133 }
134
135 static String getAppApkFilePath()
136 {
137 if (m_appApkPath != null)
138 return m_appApkPath;
139
140 try {
141 Context context = QtNative.getContext();
142 PackageManager pm = context.getPackageManager();
143 ApplicationInfo applicationInfo = pm.getApplicationInfo(context.getPackageName(), 0);
144 if (applicationInfo.splitSourceDirs != null) {
145 m_appApkPath = Arrays.stream(applicationInfo.splitSourceDirs)
146 .filter(file -> Arrays.stream(Build.SUPPORTED_ABIS)
147 .anyMatch(abi -> file.endsWith(abi.replace('-', '_') + ".apk")))
148 .findFirst()
149 .orElse(null);
150
151 if (m_appApkPath == null)
152 Log.d(QtTAG, "No ABI specific split APK found, defaulting to the main APK.");
153 }
154
155 if (m_appApkPath == null)
156 m_appApkPath = applicationInfo.sourceDir;
157 } catch (PackageManager.NameNotFoundException e) {
158 Log.e(QtTAG, "Failed to get the app APK path with " + e);
159 return null;
160 }
161 return m_appApkPath;
162 }
163
164 static class JFileInfo
165 {
166 String relativePath;
167 boolean isDir;
168 long size;
169 }
170
171 static ArrayList<JFileInfo> getApkFileInfos(String apkPath)
172 {
173 ArrayList<JFileInfo> fileInfos = new ArrayList<>();
174 HashSet<String> dirSet = new HashSet<>();
175 HashSet<String> allDirsSet = new HashSet<>();
176
177 try (ZipFile zipFile = new ZipFile(apkPath)) {
178 Enumeration<? extends ZipEntry> enumerator = zipFile.entries();
179 while (enumerator.hasMoreElements()) {
180 ZipEntry entry = enumerator.nextElement();
181 String name = entry.getName();
182
183 // Limit the listing to lib directory
184 if (name.startsWith("lib/")) {
185 JFileInfo info = new JFileInfo();
186 info.relativePath = name;
187 info.isDir = entry.isDirectory();
188 info.size = entry.getSize();
189 fileInfos.add(info);
190
191 // check directories
192 dirSet.add(name.substring(0, name.lastIndexOf("/") + 1));
193 }
194 }
195
196 // ZipFile iterator doesn't seem to add directories, so add them manually.
197 for (String path : dirSet) {
198 int index = 0;
199 while ((index = path.indexOf("/", index + 1)) != -1) {
200 String dir = path.substring(0, index);
201 allDirsSet.add(dir);
202 }
203 }
204
205 for (String dir : allDirsSet) {
206 JFileInfo info = new JFileInfo();
207 info.relativePath = dir;
208 info.isDir = true;
209 info.size = -1;
210 fileInfos.add(info);
211 }
212
213 // sort alphabetically based on the file path
214 fileInfos.sort(Comparator.comparing(info -> info.relativePath));
215 } catch (Exception e) {
216 Log.e(QtTAG, "Failed to list App's APK files with " + e);
217 }
218
219 return fileInfos;
220 }
221}
QPainter Context
static const QString context()
Definition java.cpp:396
QFuture< QtPrivate::MapResultType< Sequence, MapFunctor > > mapped(QThreadPool *pool, Sequence &&sequence, MapFunctor &&map)
GLenum GLuint GLintptr GLsizeiptr size
GLuint index
GLenum GLuint GLintptr offset
GLuint entry
GLsizei const GLchar *const * path
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
EGLContext EGLenum EGLClientBuffer buffer
EGLImageKHR EGLint * name
QHostInfo info
[0]