Skip to content

Commit 91b249b

Browse files
committed
Fix large APK archive fallback
1 parent 0554271 commit 91b249b

4 files changed

Lines changed: 46 additions & 22 deletions

File tree

acquisition/acquisition.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"errors"
1212
"fmt"
1313
"io"
14+
"os"
1415
"strings"
1516
"time"
1617

@@ -197,13 +198,15 @@ func (a *Acquisition) StreamAPKToZip(remotePath, zipPath string, processFunc fun
197198
buffer, err := a.StreamingPuller.PullToBuffer(remotePath)
198199
if err != nil {
199200
if errors.Is(err, ErrStreamingBufferMemoryLimit) && processFunc == nil {
200-
log.Debugf("APK %s exceeded streaming buffer limit; streaming directly to archive", remotePath)
201-
writer, err := a.ZipWriter.CreateFile(zipPath)
201+
log.Debugf("APK %s exceeded streaming buffer limit; staging it before archiving", remotePath)
202+
tempPath, err := a.StreamingPuller.PullToTempFile(remotePath)
202203
if err != nil {
203-
return fmt.Errorf("failed to create zip entry for APK %q: %v", remotePath, err)
204+
return fmt.Errorf("failed to pull APK %q to a temporary file: %w", remotePath, err)
204205
}
205-
if err := a.StreamingPuller.PullToWriter(remotePath, writer); err != nil {
206-
return fmt.Errorf("failed to stream APK %q to zip: %v", remotePath, err)
206+
defer os.Remove(tempPath)
207+
208+
if err := a.ZipWriter.CreateFileFromPath(zipPath, tempPath); err != nil {
209+
return fmt.Errorf("failed to add APK %q to zip: %w", remotePath, err)
207210
}
208211
return nil
209212
}

acquisition/streaming_buffer.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"errors"
1111
"fmt"
1212
"io"
13+
"os"
1314
"os/exec"
1415
"strings"
1516
)
@@ -132,6 +133,28 @@ func (sp *StreamingPuller) PullToWriter(remotePath string, writer io.Writer) err
132133
return nil
133134
}
134135

136+
// PullToTempFile pulls a file from the device into a temporary file and
137+
// returns its path. The caller is responsible for removing the file.
138+
func (sp *StreamingPuller) PullToTempFile(remotePath string) (string, error) {
139+
tempFile, err := os.CreateTemp("", "androidqf-pull-*")
140+
if err != nil {
141+
return "", fmt.Errorf("failed to create temporary file: %w", err)
142+
}
143+
tempPath := tempFile.Name()
144+
145+
if err := sp.PullToWriter(remotePath, tempFile); err != nil {
146+
_ = tempFile.Close()
147+
_ = os.Remove(tempPath)
148+
return "", fmt.Errorf("failed to pull to temporary file: %w", err)
149+
}
150+
if err := tempFile.Close(); err != nil {
151+
_ = os.Remove(tempPath)
152+
return "", fmt.Errorf("failed to close temporary file: %w", err)
153+
}
154+
155+
return tempPath, nil
156+
}
157+
135158
// BackupToBuffer creates a backup directly into memory buffer using exec-out
136159
func (sp *StreamingPuller) BackupToBuffer(arg string) (*StreamingBuffer, error) {
137160
if arg == "" {

acquisition/streaming_buffer_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"errors"
55
"os"
66
"path/filepath"
7+
"runtime"
78
"testing"
89
)
910

@@ -27,6 +28,10 @@ func TestDefaultStreamingPullerMemoryLimit(t *testing.T) {
2728
}
2829

2930
func TestPullToBufferPreservesMemoryLimitError(t *testing.T) {
31+
if runtime.GOOS == "windows" {
32+
t.Skip("uses a POSIX shell script as a fake adb executable")
33+
}
34+
3035
fakeADB := filepath.Join(t.TempDir(), "adb")
3136
if err := os.WriteFile(fakeADB, []byte("#!/bin/sh\nhead -c 1048577 /dev/zero\n"), 0o700); err != nil {
3237
t.Fatalf("WriteFile(fake adb) error = %v", err)

modules/packages.go

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -208,40 +208,33 @@ func (p *Packages) processAPKStreaming(packageName string, packageFile *adb.Pack
208208
}
209209

210210
func (p *Packages) processLargeEncryptedAPK(packageFile *adb.PackageFile, zipPath string, acq *acquisition.Acquisition, usedZipPaths map[string]struct{}) (string, error) {
211-
log.Debugf("APK %s exceeded streaming buffer limit; streaming directly to encrypted archive without certificate check", packageFile.Path)
211+
log.Debugf("APK %s exceeded streaming buffer limit; staging it before adding it to the encrypted archive without certificate check", packageFile.Path)
212212

213213
packageFile.CertificateError = "Skipped certificate check: APK exceeds streaming buffer limit"
214214
packageFile.VerifiedCertificate = false
215215

216-
zipPath = reserveUniqueZipPath(zipPath, usedZipPaths)
217-
writer, err := acq.ZipWriter.CreateFile(zipPath)
216+
tempPath, err := acq.StreamingPuller.PullToTempFile(packageFile.Path)
218217
if err != nil {
219-
return "", fmt.Errorf("failed to create zip entry for APK: %v", err)
218+
return "", fmt.Errorf("failed to pull APK to temporary file: %w", err)
220219
}
221-
if err := acq.StreamingPuller.PullToWriter(packageFile.Path, writer); err != nil {
222-
return "", fmt.Errorf("failed to stream APK to archive: %v", err)
220+
defer os.Remove(tempPath)
221+
222+
zipPath = reserveUniqueZipPath(zipPath, usedZipPaths)
223+
if err := acq.ZipWriter.CreateFileFromPath(zipPath, tempPath); err != nil {
224+
return "", fmt.Errorf("failed to add APK to archive: %w", err)
223225
}
224226
return zipPath, nil
225227
}
226228

227229
func (p *Packages) processLargeAPKFromTemp(packageFile *adb.PackageFile, keepOption, zipPath string, acq *acquisition.Acquisition, usedZipPaths map[string]struct{}) (string, bool, error) {
228230
log.Debugf("APK %s exceeded streaming buffer limit; using temporary file for certificate check", packageFile.Path)
229231

230-
tempFile, err := os.CreateTemp("", "androidqf-apk-*.apk")
232+
tempPath, err := acq.StreamingPuller.PullToTempFile(packageFile.Path)
231233
if err != nil {
232-
return "", false, fmt.Errorf("failed to create temporary APK file: %v", err)
234+
return "", false, fmt.Errorf("failed to pull APK to temporary file: %w", err)
233235
}
234-
tempPath := tempFile.Name()
235236
defer os.Remove(tempPath)
236237

237-
if err := acq.StreamingPuller.PullToWriter(packageFile.Path, tempFile); err != nil {
238-
tempFile.Close()
239-
return "", false, fmt.Errorf("failed to pull APK to temporary file: %v", err)
240-
}
241-
if err := tempFile.Close(); err != nil {
242-
return "", false, fmt.Errorf("failed to close temporary APK file: %v", err)
243-
}
244-
245238
shouldSkip, err := p.processCertificateFromPath(packageFile, keepOption, tempPath)
246239
if err != nil {
247240
return "", false, fmt.Errorf("certificate processing failed: %v", err)

0 commit comments

Comments
 (0)