F34.us
Menu

Article · 8 MIN READ

What I learned by reverse engineering Pixel Recorder exports

Google Recorder filled my Pixel with shared copies of old recordings. I investigated how those files behave, tested what stays linked to the app, and found a promising way to feed my own audio analysis server.

The storage warning that started this

I wanted a straightforward way to get recordings from my phone to my server for audio analysis. I use Google Recorder on a Pixel 8a, and getting the files out of the app was the awkward part.

Then Recorder started doing something I hadn't knowingly asked it to do: filling shared storage with copies of my recordings. Roughly 700 files appeared, and my phone hit an out-of-space warning.

My first reaction was to figure out what the hell was creating them. After moving files, renaming them, force-stopping Recorder, and comparing exports, I ended up with a much more useful discovery. This feature might provide exactly the handoff I needed for my server.

The interesting part is how it behaves. These are experiments on my Pixel 8a, with some educated guesses about the implementation. I haven't inspected Recorder's private database or decompiled its export code.

Two copies of each recording

The setting is called Access recordings in other apps. Google's help says it is enabled by default and creates additional copies of recordings for other apps to access. The originals stay in Recorder's private storage. Deleting a shared copy doesn't delete the original, and deleting the original in Recorder doesn't automatically delete the shared copy. Google's documentation also explicitly acknowledges the extra storage use.

On my phone, those copies appeared as M4A files in the shared Recordings/ directory, accessible as /sdcard/Recordings/. Here, “public” means shared storage on the phone; it doesn't mean published on the internet. Apps with the relevant access can read these files.

Recorder's Android App info showed about 11.9 GB of user data. That figure can include metadata and other app content, so it isn't an exact measurement of my audio archive. It does give some context for why automatically creating a second set of files became a problem.

The app hadn't made the consequences clear to me. “Access recordings in other apps” sounds convenient. Discovering hundreds of extra files while running out of space is a fairly unpleasant way to learn what it means.

The old recordings kept coming

At first, the shared folder contained some of my recordings, but not all of them. I moved the exported files off the phone. Then more older recordings appeared.

Eventually, the historical files stopped arriving. New recordings still produced new M4As. I also played an old recording whose shared copy I had removed; that did not recreate the file in that test.

My working explanation is that Recorder was going through an initial export of the existing archive, ran into limited space, and continued after space became available. Once it had worked through the backlog, the folder settled into receiving new recordings.

That sequence suggests a migration that can resume or retry. It doesn't establish what schedules the work or how progress is stored. A cursor through old recordings, a per-record export marker, and a queue of pending jobs could all produce something similar. I also can't rule out another reason for the backfill eventually stopping.

The practical finding is narrower and solid: on my device, this feature exported old recordings as well as new ones. Removing the first batch didn't mean the storage activity was finished.

Recorder could still find a file after I moved it

Renaming a recording inside Recorder also renamed its shared M4A. That immediately raised another question: how was it finding the right file?

I used CX File Explorer to change things outside Recorder and tested progressively less obvious cases.

What I changed What happened when I renamed the recording in Recorder
Renamed the shared M4A externally Recorder renamed the correct file again
Force-stopped Recorder, renamed the file externally, then reopened Recorder The association still worked
Moved the shared file from Recordings/ into Downloads Recorder still renamed the moved file

That last result was the most interesting. A simple lookup using the original filename and directory wouldn't explain it. Force Stop also made a purely in-memory association an insufficient explanation.

Something durable was preserving the relationship, or Recorder had a way to rediscover the file.

My leading explanation is MediaStore

Android's MediaStore provides media records with IDs and content URIs. Apps can update file properties through a ContentResolver; Android documents DISPLAY_NAME and RELATIVE_PATH as the fields to use when creating or updating media files. Android's shared media documentation describes those mechanisms.

Recorder could save a content URI for each exported recording and use it later to rename the corresponding media item. Conceptually, the association might look like this:

Private recording
    title: Meeting notes
    exported media: content://media/.../8427

Shared media item 8427
    filename: Meeting notes.m4a
    location: Recordings/

Those fields and the URI are illustrative. I did not extract them from Recorder.

This model fits the rename and restart results. It could also explain the move if CX File Explorer's operation preserved the media item's identity. I haven't checked the actual MediaStore IDs, and another file manager—or a move implemented as copy-and-delete—could behave differently. A different persistent identifier or a rediscovery mechanism remains possible.

The observation is that Recorder found the moved file. A stored MediaStore URI is my hypothesis for how.

Independent copies with some behavior still linked

Deleting shared files left the recordings accessible inside Recorder. Deleting recordings inside the app left their shared copies behind. Yet title changes could still reach those copies, even after the external changes above.

That combination matters. I would treat the shared files as independent exports with some continuing association to Recorder. The rename behavior doesn't establish that every later edit, transcription update, or deletion will be synchronized.

It also helps explain why a removed public file might stay removed. Recorder could remember that it had already exported that recording, or retain a reference to a media item that no longer exists. Either could allow “export completed” and “exported file still exists” to be different states.

I haven't established whether Recorder actively notices deletion. What I observed is that replaying one old recording did not regenerate its removed copy. That's useful evidence for using the folder as temporary staging, but it doesn't prove that no future update or setting change could export it again.

The automatic export matched the manual export exactly

The most useful test was also the simplest: I manually exported a recording as M4A and compared it with the automatically created M4A for that same recording.

They were byte-for-byte identical.

That establishes equality across the complete exported container for the pair I tested, including whatever metadata it contained. It doesn't establish which metadata fields Recorder includes, or guarantee the same result for every edited or imported recording.

For my use case, though, this was a big deal. The automatic route had produced exactly the file I would otherwise have obtained manually. I could stop treating the shared copy as an unknown alternative export format.

A repeatable comparison is:

sha256sum automatic.m4a manual.m4a
cmp automatic.m4a manual.m4a && echo 'Identical'

Creation times and any embedded transcription data would be useful to my analysis pipeline too. Identical files preserve whatever is there, but identifying those fields needs a separate inspection of the container.

A useful handoff to my server

Once I understood the copies, the intended workflow became straightforward:

flowchart TD
    Recorder[Recorder private archive] --> Shared[Shared M4A in Recordings]
    Shared --> Transfer[FolderSync upload]
    Transfer --> Server[My server]
    Server --> Analysis[Audio analysis and indexing]

The shared folder can act as an outbox. Recorder creates the M4A, FolderSync transfers it to my server, and the server feeds it into the audio processing workflow. The transfer path can work without routing the recordings through Google's cloud backup.

After a verified transfer, the shared copy can be removed while the private recording stays on the phone. That's the behavior my deletion tests support; configuring and verifying the transfer cleanup is a separate part of putting this into operation.

There are a few consequences I'd build around. A file appearing in the folder shouldn't automatically be treated as a completed write. I saw variable appearance timing, but didn't isolate Recorder's write timing from the file manager's refresh behavior. The uploader needs a settling or completion check.

Filenames can also change. Recorder may rename a file before or during a transfer, and a rename after the shared copy is gone won't necessarily reach the server. I'd keep filenames as useful labels, use hashes to identify exact duplicates, and preserve original recording metadata where available.

Finally, this should be an upload-and-archive workflow with deletion only after confirmed delivery. A two-way mirror would give deletion a very different meaning. The useful property here is that I can clear the exported staging files without clearing my Recorder library.

What I would test next

The next useful experiment is to inspect MediaStore row IDs before and after the same rename and move operations. That would test the leading explanation much more directly than watching filenames.

I'd also repeat the byte comparison with edited recordings and inspect how transcription changes affect an existing export. Those are the cases that matter before treating this as a dependable ingestion interface across the whole library.

For now, I have enough evidence to see a promising route from Recorder to my own processing stack, and enough unanswered questions to avoid pretending I've recovered Google's implementation.

I still think creating hundreds of extra files deserves a much clearer explanation before it happens. An estimate of the storage required, an explicit choice about exporting the existing archive, and a visible indication of progress would have saved me a lot of confusion.

But once I worked through the behavior, I could see the value. The feature that filled my phone with unexpected copies also gave me a way to get recordings out automatically. I just had to reverse-engineer enough of it to understand what I could rely on.

F34.us Background Image