Author Archives:

Security for the Quantum Era: Implementing Post-Quantum Cryptography in Android

Modern digital security is at a turning point. We are on the threshold of using quantum computers to solve "impossible" problems in drug discovery, materials science, and energy—tasks that even the most powerful classical supercomputers cannot handle. However, the same unique ability to consider different options simultaneously also allows these machines to bypass our current digital locks. This puts the public-key cryptography we’ve relied on for decades at risk, potentially compromising everything from bank transfers to trade secrets. To secure our future, it is vital to adopt the new Post-Quantum Cryptography (PQC) standards National Institute of Standards and Technology (NIST) is urging before large-scale, fault-tolerant quantum computers become a reality.

To stay ahead of the curve, the technology industry must undertake a proactive, multi-year migration to Post-Quantum Cryptography (PQC). We have been preparing for a post-quantum world since 2016, conducting pioneering experiments with post-quantum cryptography, rolling out post-quantum capabilities in our products, and sharing our expertise through threat models and technical papers. For Android, the objective extends beyond patching individual applications or transport protocols. The imperative is to ensure that the entire platform architecture is resilient for the decades to come.

We are beginning tests of PQC enhancements starting in the next Android 17 beta, followed by general availability in the Android 17 production release. This deployment introduces a comprehensive architectural upgrade that is being rolled out across the operating system. By integrating the recently finalized NIST PQC standards deep into the platform, we’re establishing a new, quantum-resistant chain of trust. This chain of trust secures the platform continuously—from the moment the OS powers on, to the execution of applications distributed globally. Android is swapping today’s digital locks for advanced encryption to help enhance the security of every app you download—no matter how powerful future supercomputers get.

Securing the foundation: Verified boot and hardware trust

Security on any computing device begins when the hardware starts; if the underlying operating system is compromised, all subsequent software protections fail. As quantum computing advances, adversaries could potentially forge digital signatures to bypass these foundational integrity checks. To secure the platform against this looming threat, Android 17 introduces two major post-quantum cryptographic (PQC) upgrades:

  1. Upgrading Android Verified Boot (AVB): The AVB library is integrating the Module-Lattice-Based Digital Signature Algorithm (ML-DSA). This provides quantum-resistant digital signatures, ensuring the software loaded during the boot sequence remains highly resistant to unauthorized modification.
  2. Migrating Remote Attestation: Android 17 begins the transition of Remote Attestation to a fully PQC-compliant architecture under the current standards. By updating KeyMint's certificate chains to support quantum-resistant algorithms, devices can securely prove their state to relying parties, maintaining trust in a post-quantum environment.

Empowering developers: Android Keystore updates

Protecting the underlying operating system is only the first layer of defense; developers must be equipped with the cryptographic primitives necessary to leverage PQC keys and establish robust identity verification.

Implementing lattice-based cryptography, which requires significantly larger key sizes and memory footprints than classical elliptic curve cryptography, within the severely resource-constrained Trusted Execution Environment (TEE), represents a major engineering achievement. This capability is designed to support the hardware roots of trust and can now generate and verify post-quantum signatures.

Building on this hardware foundation, Android 17 updates Android Keystore to natively support ML-DSA. This allows applications to leverage quantum-safe signatures entirely within the device’s secure hardware, isolating sensitive key material from the main operating system. The SDK exposes both ML-DSA-65, and ML-DSA-87, enabling developers to seamlessly integrate these using the standard KeyPairGenerator API. This establishes a new era of identity and authentication for the app ecosystem without requiring developers to engineer proprietary cryptographic implementations.

Ecosystem scale: Bringing hybrid signing to Google Play apps and games

Android is committed to ensuring the platform is PQC resistant and extending the chain of PQC resistance to application signatures. The mechanisms used to verify the authenticity of applications are being upgraded to ensure that app installations and subsequent updates are strictly tamper-proof against quantum-enabled signature forgery. The platform will verify PQC signatures over APKs to enable this chain of trust.

To bring these critical protections to the wider developer community with minimal friction, the transition will be supported through Play App Signing. This approach provides an immediate bridge to quantum safety for the majority of active installs. Google Play will let developers automatically generate 'hybrid' signature blocks that combine classical and PQC keys.

Updating keys across billions of active devices is a complex operational endeavor. Play App Signing leverages Google Cloud KMS, which helps ensure industry-leading compliance standards, to secure signing keys. By managing signing keys securely in the cloud, Google Play enables developers to seamlessly upgrade their app security to PQC standards without the burden of complex, manual key management.

During the Android 17 release cycle, Google Play will handle the generation of quantum-safe ML-DSA signing keys for new apps and existing apps that opt-in, independent of the applications target API . Later, developers will be able to choose their own classical and ML-DSA signing keys and delegate them to Google Play for their hybrid key upgrade. To promote security best practices, Google Play will also start prompting developers to upgrade their signing keys at least every two years.

The cryptographic roadmap: From authenticity to privacy

Google’s post-quantum transition began in 2016, and Android 17 marks the first phase of Android’s post-quantum transition:

  • Securing the foundation: We are upholding the integrity of our attestation and Chain of Trust by incorporating ML-DSA into Android Verified Boot.
  • Empower Developers: The inclusion of ML-DSA support within Android Keystore and Play App Signing allows developers to safeguard their users and application.
  • Ecosystem Scale: By using hybrid signatures for APKs, developers can create a protected transition that preserves current trust while adding post-quantum defenses to block unauthorized updates.

Our roadmap further integrates post-quantum key encapsulation into KeyMint, Key Attestation and Remote Key Provisioning. This evolution is intended to bolster the security of the entire identity lifecycle—from hardware-level DICE measurements to our remote attestation servers—ensuring the Android ecosystem remains resilient and private against the quantum threats of tomorrow.

Stable Channel Update for ChromeOS / ChromeOS Flex

The ChromeOS Stable channel is being updated to OS version 16581.42.0 (Browser version 146.0.7680.169) for most ChromeOS devices.

If you find new issues, please let us know one of the following ways:
  1. File a bug
  2. Visit our ChromeOS communities

    1. General: Chromebook Help Community

    2. Beta Specific: ChromeOS Beta Help Community

  3. Report an issue or send feedback on Chrome

  4. Interested in switching channels? Find out how.

Luis Menezes

Google ChromeOS

How GFiber in-home installation works

Thumbnail


GFiber offers two installation paths to connect your home to our fiber-optic network: professional installation by a technician or a simple self-setup for eligible addresses. Both options include the necessary equipment, such as a Fiber Jack and an advanced Wi-Fi router, at no additional cost.[1]

Professional installation: What to expect

Professional installation is available for all GFiber customers. During this process, a technician visits your home to install the Fiber Jack and set up your router and whole home Wi-Fi network. The technician will also perform a battery of signature diagnostic tests to ensure performance meets GFiber’s high standards for speed, coverage and connectivity. The tech will also assess your home’s wiring and if eligible, hardwire your home office, gaming station or up to 2 other highest use areas for Home and Edge customers. 

The role of the Fiber Jack

The Fiber Jack is a device mounted inside your home that translates our fiber-optic signal from the network into a connection your router can understand. GFiber owns and maintains this equipment, so there is no separate purchase required.

Step-by-step professional setup

  1. Schedule your appointment: Pick a time at fiber.google.com; appointments typically last about two hours.

  2. Fiber Jack installation: Your technician mounts the device on an interior wall, often near a standard electrical outlet. Have a preferred location for the Fiber Jack? Let your technician know and together you can discuss placement. If you live in an apartment complex, your Fiber Jack may be installed in a media closet.

  3. Router activation: The technician connects the Wi-Fi router to the Fiber Jack using an Ethernet cable to activate your service.[2] 

  4. Connection confirmation: We’ll make sure your connection is live, verify performance meets or exceeds our standards and help you get into the GFiber App so you can manage your network.

Note: Someone 18 or older needs to be home for the appointment. There’s no installation fee for this service.

Equipment and support

GFiber provides specific hardware based on your selected product to ensure optimal performance.

Equipment

Included With

Fiber Jack (ONT)

All products

GFiber Wi-Fi 6E Router

Core 1 Gig

GFiber Wi-Fi 7 Router

Home 3 Gig and Edge 8 Gig

Mesh Wi-Fi Extenders

Depends on what you need for the best whole home coverage. More is not necessarily better and your technician will help determine the best set up. Up to 1 extender included with Core 1 Gig; 2 with Home 3 Gig and Edge 8 Gig


If you experience issues or run into a snag, help is just a tap away in the GFiber App, online, or over the phone. Learn about the step-by-step process for installing GFiber services at your home in our Help Center, here.


[1] No extra cost: All GFiber construction, installation, and if necessary, repair activities are included at no extra cost. 

[2] Third-party routers: Customers may use their own router by connecting it to the Fiber Jack, though GFiber diagnostics and support may be limited.

Contact Picker: Privacy-First Contact Sharing

Posted by Roxanna Aliabadi Walker, Senior Product Manager


Privacy and user control remain at the heart of the Android experience. Just as the photo picker made media sharing secure and easy to implement, we are now bringing that same level of privacy, simplicity, and great user experience to contact selection.

A New Standard for Contact Privacy

Historically, applications requiring access to a specific user's contacts relied on the broad READ_CONTACTS permission. While functional, this approach often granted apps more data than necessary. The new Android Contact Picker, introduced in Android 17, changes this dynamic by providing a standardized, secure, and searchable interface for contact selection.

This feature allows users to grant apps access only to the specific contacts they choose, aligning with Android's commitment to data transparency and minimized permission footprints.



How It Works

Developers can integrate the Contact Picker using the Intent.ACTION_PICK_CONTACTS intent. This updated API offers several powerful capabilities:

  • Granular Data Requests: Apps can specify exactly which fields they need, such as phone numbers or email addresses, rather than receiving the entire contact record.

  • Multi-Selection Support: The picker supports both single and multiple contact selections, giving developers more flexibility for features like group invitations.

  • Selection Limits: Developers can set custom limits on the number of contacts a user can select at one time.

  • Temporary Access: Upon selection, the system returns a Session URI that provides temporary read access to the requested data, ensuring that access does not persist longer than necessary.

  • Access to other profiles: When using this new intent, the interface will allow users to select contents from other user profiles such as a work profile, cloned profile or a private space.

  • Optimized Performance: The Contact Picker returns a single Uri that allows for collective result querying, eliminating the need to query individual contact Uri separately as required by ACTION_PICK. This efficiency further reduces system overhead by utilizing a single Binder transaction.

Backward Compatibility and Implementation

For devices running Android 17 or higher, the system automatically upgrades legacy ACTION_PICK intents that specify contact data types to the new, more secure interface. However, to take full advantage of advanced features like multi-selection, developers are encouraged to update their implementation code and utilize the ContentResolver to query the returned Session URI.

Integrate the contact pickerTo integrate the Contact Picker, developers use the 
 ACTION_PICK_CONTACTS intent. Below is a code example demonstrating how to launch the picker and request specific data fields, such as email and phone numbers.

// State to hold the list of selected contacts
var contacts by remember { mutableStateOf<List<Contact>>(emptyList()) }

// Launcher for the Contact Picker intent
val pickContact = rememberLauncherForActivityResult(StartActivityForResult()) {
    if (it.resultCode == Activity.RESULT_OK) {
        val resultUri = it.data?.data ?: return@rememberLauncherForActivityResult

        // Process the result URI in a background thread
        coroutine.launch {
            contacts = processContactPickerResultUri(resultUri, context)
        }
    }
}

// Define the specific contact data fields you need
val requestedFields = arrayListOf(
    Email.CONTENT_ITEM_TYPE,
    Phone.CONTENT_ITEM_TYPE,
)

// Set up the intent for the Contact Picker
val pickContactIntent = Intent(ACTION_PICK_CONTACTS).apply {
    putExtra(EXTRA_PICK_CONTACTS_SELECTION_LIMIT, 5)
    putStringArrayListExtra(
        EXTRA_PICK_CONTACTS_REQUESTED_DATA_FIELDS,
        requestedFields
    )
    putExtra(EXTRA_PICK_CONTACTS_MATCH_ALL_DATA_FIELDS, false)
}

// Launch the picker
pickContact.launch(pickContactIntent)

After the user makes a selection, the app processes the result by querying the returned Session URI to extract the requested contact information.

// Data class representing a parsed Contact with selected details
data class Contact(val id: String, val name: String, val email: String?, val phone: String?)

// Helper function to query the content resolver with the URI returned by the Contact Picker.
// Parses the cursor to extract contact details such as name, email, and phone number
private suspend fun processContactPickerResultUri(
    sessionUri: Uri,
    context: Context
): List<Contact> = withContext(Dispatchers.IO) {
    // Define the columns we want to retrieve from the ContactPicker ContentProvider
    val projection = arrayOf(
        ContactsContract.Contacts._ID,
        ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
        ContactsContract.Data.MIMETYPE, // Type of data (e.g., email or phone)
        ContactsContract.Data.DATA1, // The actual data (Phone number / Email string)
    )

    val results = mutableListOf<Contact>()

    // Note: The Contact Picker Session Uri doesn't support custom selection & selectionArgs.
    context.contentResolver.query(sessionUri, projection, null, null, null)?.use { cursor ->
        // Get the column indices for our requested projection
        val contactIdIdx = cursor.getColumnIndex(ContactsContract.Contacts._ID)
        val mimeTypeIdx = cursor.getColumnIndex(ContactsContract.Data.MIMETYPE)
        val nameIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)
        val data1Idx = cursor.getColumnIndex(ContactsContract.Data.DATA1)

        while (cursor.moveToNext()) {
            val contactId = cursor.getString(contactIdIdx)
            val mimeType = cursor.getString(mimeTypeIdx)
            val name = cursor.getString(nameIdx) ?: ""
            val data1 = cursor.getString(data1Idx) ?: ""

            // Determine if the current row represents an email or a phone number
            val email = if (mimeType == Email.CONTENT_ITEM_TYPE) data1 else null
            val phone = if (mimeType == Phone.CONTENT_ITEM_TYPE) data1 else null

            // Add the parsed contact to our results list
            results.add(Contact(contactId, name, email, phone))
        }
    }

    return@withContext results
}


Check out the full documentation here.

Best Practices for Developers

To provide the best user experience and maintain high security standards, we recommend the following:

  • Data Minimization: Only request the specific data fields (e.g., email) your app needs.

  • Immediate Persistence: Persist selected data immediately, as the Session URI access is temporary.

Contact Picker: Privacy-First Contact Sharing

Posted by Roxanna Aliabadi Walker, Senior Product Manager


Privacy and user control remain at the heart of the Android experience. Just as the photo picker made media sharing secure and easy to implement, we are now bringing that same level of privacy, simplicity, and great user experience to contact selection.

A New Standard for Contact Privacy

Historically, applications requiring access to a specific user's contacts relied on the broad READ_CONTACTS permission. While functional, this approach often granted apps more data than necessary. The new Android Contact Picker, introduced in Android 17, changes this dynamic by providing a standardized, secure, and searchable interface for contact selection.

This feature allows users to grant apps access only to the specific contacts they choose, aligning with Android's commitment to data transparency and minimized permission footprints.



How It Works

Developers can integrate the Contact Picker using the Intent.ACTION_PICK_CONTACTS intent. This updated API offers several powerful capabilities:

  • Granular Data Requests: Apps can specify exactly which fields they need, such as phone numbers or email addresses, rather than receiving the entire contact record.

  • Multi-Selection Support: The picker supports both single and multiple contact selections, giving developers more flexibility for features like group invitations.

  • Selection Limits: Developers can set custom limits on the number of contacts a user can select at one time.

  • Temporary Access: Upon selection, the system returns a Session URI that provides temporary read access to the requested data, ensuring that access does not persist longer than necessary.

  • Access to other profiles: When using this new intent, the interface will allow users to select contents from other user profiles such as a work profile, cloned profile or a private space.

  • Optimized Performance: The Contact Picker returns a single Uri that allows for collective result querying, eliminating the need to query individual contact Uri separately as required by ACTION_PICK. This efficiency further reduces system overhead by utilizing a single Binder transaction.

Backward Compatibility and Implementation

For devices running Android 17 or higher, the system automatically upgrades legacy ACTION_PICK intents that specify contact data types to the new, more secure interface. However, to take full advantage of advanced features like multi-selection, developers are encouraged to update their implementation code and utilize the ContentResolver to query the returned Session URI.

Integrate the contact pickerTo integrate the Contact Picker, developers use the 
 ACTION_PICK_CONTACTS intent. Below is a code example demonstrating how to launch the picker and request specific data fields, such as email and phone numbers.

// State to hold the list of selected contacts
var contacts by remember { mutableStateOf<List<Contact>>(emptyList()) }

// Launcher for the Contact Picker intent
val pickContact = rememberLauncherForActivityResult(StartActivityForResult()) {
    if (it.resultCode == Activity.RESULT_OK) {
        val resultUri = it.data?.data ?: return@rememberLauncherForActivityResult

        // Process the result URI in a background thread
        coroutine.launch {
            contacts = processContactPickerResultUri(resultUri, context)
        }
    }
}

// Define the specific contact data fields you need
val requestedFields = arrayListOf(
    Email.CONTENT_ITEM_TYPE,
    Phone.CONTENT_ITEM_TYPE,
)

// Set up the intent for the Contact Picker
val pickContactIntent = Intent(ACTION_PICK_CONTACTS).apply {
    putExtra(EXTRA_PICK_CONTACTS_SELECTION_LIMIT, 5)
    putStringArrayListExtra(
        EXTRA_PICK_CONTACTS_REQUESTED_DATA_FIELDS,
        requestedFields
    )
    putExtra(EXTRA_PICK_CONTACTS_MATCH_ALL_DATA_FIELDS, false)
}

// Launch the picker
pickContact.launch(pickContactIntent)

After the user makes a selection, the app processes the result by querying the returned Session URI to extract the requested contact information.

// Data class representing a parsed Contact with selected details
data class Contact(val id: String, val name: String, val email: String?, val phone: String?)

// Helper function to query the content resolver with the URI returned by the Contact Picker.
// Parses the cursor to extract contact details such as name, email, and phone number
private suspend fun processContactPickerResultUri(
    sessionUri: Uri,
    context: Context
): List<Contact> = withContext(Dispatchers.IO) {
    // Define the columns we want to retrieve from the ContactPicker ContentProvider
    val projection = arrayOf(
        ContactsContract.Contacts._ID,
        ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
        ContactsContract.Data.MIMETYPE, // Type of data (e.g., email or phone)
        ContactsContract.Data.DATA1, // The actual data (Phone number / Email string)
    )

    val results = mutableListOf<Contact>()

    // Note: The Contact Picker Session Uri doesn't support custom selection & selectionArgs.
    context.contentResolver.query(sessionUri, projection, null, null, null)?.use { cursor ->
        // Get the column indices for our requested projection
        val contactIdIdx = cursor.getColumnIndex(ContactsContract.Contacts._ID)
        val mimeTypeIdx = cursor.getColumnIndex(ContactsContract.Data.MIMETYPE)
        val nameIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)
        val data1Idx = cursor.getColumnIndex(ContactsContract.Data.DATA1)

        while (cursor.moveToNext()) {
            val contactId = cursor.getString(contactIdIdx)
            val mimeType = cursor.getString(mimeTypeIdx)
            val name = cursor.getString(nameIdx) ?: ""
            val data1 = cursor.getString(data1Idx) ?: ""

            // Determine if the current row represents an email or a phone number
            val email = if (mimeType == Email.CONTENT_ITEM_TYPE) data1 else null
            val phone = if (mimeType == Phone.CONTENT_ITEM_TYPE) data1 else null

            // Add the parsed contact to our results list
            results.add(Contact(contactId, name, email, phone))
        }
    }

    return@withContext results
}


Check out the full documentation here.

Best Practices for Developers

To provide the best user experience and maintain high security standards, we recommend the following:

  • Data Minimization: Only request the specific data fields (e.g., email) your app needs.

  • Immediate Persistence: Persist selected data immediately, as the Session URI access is temporary.

Safeguarded guest admit flow in Google Meet

The new safeguarded guest admit flow assists hosts in meetings when they respond to users who ask to join meetings (also known as ”knocking”). This makes it easier for hosts to handle large volumes of requests and helps reduce the attention and time needed.

Meeting hosts will now get those requests presented in two separate queues. A new second queue now shows requests from connections where the host is more likely to need a closer look before deciding to approve them into the meeting. The default action for entries in this queue is to deny entry.

Hosts/co-hosts still remain in control and are always free to take another action than the default suggested.

New notifications and people panel updates for the improved admit flow

Getting started

  • Admins: There is no admin control for this feature.
  • End users: Visit the Help Center to learn more.

Rollout pace

Availability

  • Available to all Google Workspace customers, Workspace Individual subscribers, and users with personal Google accounts

Resources

Chrome Dev for Desktop Update

The Dev channel has been updated to 148.0.7743.0 for Windows, Mac and Linux.

A partial list of changes is available in the Git log. Interested in switching release channels? Find out how. If you find a new issue, please let us know by filing a bug. The community help forum is also a great place to reach out for help or learn about common issues.

Chrome Release Team
Google Chrome