Olivier Pietquin

273 papers A* 40A 33B 10C 2Misc 13Journal 111Unranked 60
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Ilyass Moummad, Marius Miron, Lukas Rauch, David Robinson, Alexis Joly, Olivier Pietquin, Emmanuel Chemla, Matthieu Geist
2026 J jnl
CoRR
Lorenzo Magnino, Jiacheng Shen, Matthieu Geist, Olivier Pietquin, Mathieu Laurière
2026 J jnl
CoRR
Ilyass Moummad, Marius Miron, David Robinson, Kawtar Zaher, Hervé Goëau, Olivier Pietquin, Pierre Bonnet, Emmanuel Chemla, Matthieu Geist, Alexis Joly
2025 Misc conf
ICASSP
Marius Miron, Sara Keen, Jen-Yu Liu, Benjamin Hoffman, Masato Hagiwara, Olivier Pietquin, Felix Effenberger, Maddie Cusimano
2025 J jnl
CoRR
Jules Cauzinille, Marius Miron, Olivier Pietquin, Masato Hagiwara, Ricard Marxer, Arnaud Rey, Benoît Favre
2025 A* conf
ICLR
David Robinson, Marius Miron, Masato Hagiwara, Olivier Pietquin
2025 conf
CDC
Zida Wu, Mathieu Laurière, Matthieu Geist, Olivier Pietquin, Ankur Mehta
2025 J jnl
CoRR
Zida Wu, Mathieu Laurière, Matthieu Geist, Olivier Pietquin, Ankur Mehta
2025 J jnl
CoRR
Louis Mahon, Benjamin Hoffman, Logan S. James, Maddie Cusimano, Masato Hagiwara, Sarah C. Woolley, Olivier Pietquin
2025 A* conf
ICLR
Eugene Choi, Arash Ahmadian, Matthieu Geist, Olivier Pietquin, Mohammad Gheshlaghi Azar
2025 J jnl
CoRR
Pierre Clavier, Nathan Grinsztajn, Raphaël Avalos, Yannis Flet-Berliac, Irem Ergün, Omar Darwiche Domingues, Eugene Tarassov, Olivier Pietquin, Pierre H. Richemond, Florian Strub, Matthieu Geist
2025 J jnl
CoRR
Benjamin Hoffman, David Robinson, Marius Miron, Vittorio Baglione, Daniela Canestrari, Damian Elias, Eva Trapote, Olivier Pietquin
2025 J jnl
CoRR
Marius Miron, David Robinson, Milad Alizadeh, Ellen Gilsenan-McMahon, Gagan Narula, Emmanuel Chemla, Maddie Cusimano, Felix Effenberger, Masato Hagiwara, Benjamin Hoffman, Sara Keen, Diane Kim, Jane Lawton, Jen-Yu Liu, Aza Raskin, Olivier Pietquin, Matthieu Geist
2024 J jnl
CoRR
Nathan Grinsztajn, Yannis Flet-Berliac, Mohammad Gheshlaghi Azar, Florian Strub, Bill Wu, Eugene Choi, Chris Cremer, Arash Ahmadian, Yash Chandak, Olivier Pietquin, Matthieu Geist
2024 J jnl
CoRR
Arash Ahmadian, Chris Cremer, Matthias Gallé, Marzieh Fadaee, Julia Kreutzer, Olivier Pietquin, Ahmet Üstün, Sara Hooker
2024 conf
ACL (1)
Arash Ahmadian, Chris Cremer, Matthias Gallé, Marzieh Fadaee, Julia Kreutzer, Olivier Pietquin, Ahmet Üstün, Sara Hooker
2024 J jnl
CoRR
Marius Miron, Sara Keen, Jen-Yu Liu, Benjamin Hoffman, Masato Hagiwara, Olivier Pietquin, Felix Effenberger, Maddie Cusimano
2024 A* conf
EMNLP
Yannis Flet-Berliac, Nathan Grinsztajn, Florian Strub, Eugene Choi, Bill Wu, Chris Cremer, Arash Ahmadian, Yash Chandak, Mohammad Gheshlaghi Azar, Olivier Pietquin, Matthieu Geist
2024 J jnl
CoRR
Yannis Flet-Berliac, Nathan Grinsztajn, Florian Strub, Eugene Choi, Chris Cremer, Arash Ahmadian, Yash Chandak, Mohammad Gheshlaghi Azar, Olivier Pietquin, Matthieu Geist
2024 conf
ACL (Findings)
Mathieu Rita, Florian Strub, Rahma Chaabouni, Paul Michel, Emmanuel Dupoux, Olivier Pietquin
2024 J jnl
CoRR
Mathieu Rita, Florian Strub, Rahma Chaabouni, Paul Michel, Emmanuel Dupoux, Olivier Pietquin
2024 J jnl
CoRR
Mathieu Rita, Paul Michel, Rahma Chaabouni, Olivier Pietquin, Emmanuel Dupoux, Florian Strub
2024 A* conf
AAAI
Kai Cui, Gökçe Dayanikli, Mathieu Laurière, Matthieu Geist, Olivier Pietquin, Heinz Koeppl
2024 A* conf
ICML
Geoffrey Cideron, Sertan Girgin, Mauro Verzetti, Damien Vincent, Matej Kastelic, Zalán Borsos, Brian McWilliams, Victor Ungureanu, Olivier Bachem, Olivier Pietquin, Matthieu Geist, Léonard Hussenot, Neil Zeghidour, Andrea Agostinelli
2024 J jnl
CoRR
Geoffrey Cideron, Sertan Girgin, Mauro Verzetti, Damien Vincent, Matej Kastelic, Zalán Borsos, Brian McWilliams, Victor Ungureanu, Olivier Bachem, Olivier Pietquin, Matthieu Geist, Léonard Hussenot, Neil Zeghidour, Andrea Agostinelli
2024 J jnl
CoRR
David Robinson, Marius Miron, Masato Hagiwara, Olivier Pietquin
2024 A conf
AAMAS
Zida Wu, Mathieu Laurière, Samuel Jia Cong Chua, Matthieu Geist, Olivier Pietquin, Ankur Mehta
2024 J jnl
CoRR
Zida Wu, Mathieu Laurière, Samuel Jia Cong Chua, Matthieu Geist, Olivier Pietquin, Ankur Mehta
2024 J jnl
CoRR
Eugene Choi, Arash Ahmadian, Matthieu Geist, Olivier Pietquin, Mohammad Gheshlaghi Azar
2023 J jnl
IEEE ACM Trans. Audio Speech Lang. Process.
Zalán Borsos, Raphaël Marinier, Damien Vincent, Eugene Kharitonov, Olivier Pietquin, Matthew Sharifi, Dominik Roblek, Olivier Teboul, David Grangier, Marco Tagliasacchi, Neil Zeghidour
2023 conf
ACL (1)
Paul Roit, Johan Ferret, Lior Shani, Roee Aharoni, Geoffrey Cideron, Robert Dadashi, Matthieu Geist, Sertan Girgin, Léonard Hussenot, Orgad Keller, Nikola Momchev, Sabela Ramos Garea, Piotr Stanczyk, Nino Vieillard, Olivier Bachem, Gal Elidan, Avinatan Hassidim, Olivier Pietquin, Idan Szpektor
2023 J jnl
CoRR
Paul Roit, Johan Ferret, Lior Shani, Roee Aharoni, Geoffrey Cideron, Robert Dadashi, Matthieu Geist, Sertan Girgin, Léonard Hussenot, Orgad Keller, Nikola Momchev, Sabela Ramos, Piotr Stanczyk, Nino Vieillard, Olivier Bachem, Gal Elidan, Avinatan Hassidim, Olivier Pietquin, Idan Szpektor
2023 J jnl
CoRR
Geoffrey Cideron, Baruch Tabanpour, Sebastian Curi, Sertan Girgin, Léonard Hussenot, Gabriel Dulac-Arnold, Matthieu Geist, Olivier Pietquin, Robert Dadashi
2023 J jnl
CoRR
Kai Cui, Gökçe Dayanikli, Mathieu Laurière, Matthieu Geist, Olivier Pietquin, Heinz Koeppl
2023 A* conf
NeurIPS
Giorgia Ramponi, Pavel Kolev, Olivier Pietquin, Niao He, Mathieu Laurière, Matthieu Geist
2023 J jnl
CoRR
Giorgia Ramponi, Pavel Kolev, Olivier Pietquin, Niao He, Mathieu Laurière, Matthieu Geist
2023 A* conf
ICML
Toshinori Kitamura, Tadashi Kozuno, Yunhao Tang, Nino Vieillard, Michal Valko, Wenhao Yang, Jincheng Mei, Pierre Ménard, Mohammad Gheshlaghi Azar, Rémi Munos, Olivier Pietquin, Matthieu Geist, Csaba Szepesvári, Wataru Kumagai, Yutaka Matsuo
2023 J jnl
CoRR
Toshinori Kitamura, Tadashi Kozuno, Yunhao Tang, Nino Vieillard, Michal Valko, Wenhao Yang, Jincheng Mei, Pierre Ménard, Mohammad Gheshlaghi Azar, Rémi Munos, Olivier Pietquin, Matthieu Geist, Csaba Szepesvári, Wataru Kumagai, Yutaka Matsuo
2023 J jnl
CoRR
Chris Donahue, Antoine Caillon, Adam Roberts, Ethan Manilow, Philippe Esling, Andrea Agostinelli, Mauro Verzetti, Ian Simon, Olivier Pietquin, Neil Zeghidour, Jesse H. Engel
2023 J jnl
CoRR
Eugene Kharitonov, Damien Vincent, Zalán Borsos, Raphaël Marinier, Sertan Girgin, Olivier Pietquin, Matthew Sharifi, Marco Tagliasacchi, Neil Zeghidour
2023 J jnl
Trans. Assoc. Comput. Linguistics
Eugene Kharitonov, Damien Vincent, Zalán Borsos, Raphaël Marinier, Sertan Girgin, Olivier Pietquin, Matt Sharifi, Marco Tagliasacchi, Neil Zeghidour
2022 J jnl
CoRR
Zalán Borsos, Raphaël Marinier, Damien Vincent, Eugene Kharitonov, Olivier Pietquin, Matthew Sharifi, Olivier Teboul, David Grangier, Marco Tagliasacchi, Neil Zeghidour
2022 J jnl
CoRR
Alexis Jacq, Manu Orsini, Gabriel Dulac-Arnold, Olivier Pietquin, Matthieu Geist, Olivier Bachem
2022 A conf
AAMAS
Matthieu Geist, Julien Pérolat, Mathieu Laurière, Romuald Elie, Sarah Perrin, Olivier Bachem, Rémi Munos, Olivier Pietquin
2022 A* conf
ICML
Robert Dadashi, Léonard Hussenot, Damien Vincent, Sertan Girgin, Anton Raichuk, Matthieu Geist, Olivier Pietquin
2022 A* conf
NeurIPS
Mathieu Rita, Corentin Tallec, Paul Michel, Jean-Bastien Grill, Olivier Pietquin, Emmanuel Dupoux, Florian Strub
2022 J jnl
CoRR
Mathieu Rita, Corentin Tallec, Paul Michel, Jean-Bastien Grill, Olivier Pietquin, Emmanuel Dupoux, Florian Strub
2022 A* conf
AAAI
Sarah Perrin, Mathieu Laurière, Julien Pérolat, Romuald Élie, Matthieu Geist, Olivier Pietquin
2022 A conf
AISTATS
Nino Vieillard, Marcin Andrychowicz, Anton Raichuk, Olivier Pietquin, Matthieu Geist
2022 J jnl
CoRR
Tadashi Kozuno, Wenhao Yang, Nino Vieillard, Toshinori Kitamura, Yunhao Tang, Jincheng Mei, Pierre Ménard, Mohammad Gheshlaghi Azar, Michal Valko, Rémi Munos, Olivier Pietquin, Matthieu Geist, Csaba Szepesvári
2022 A conf
AAMAS
Alexis Jacq, Johan Ferret, Olivier Pietquin, Matthieu Geist
2022 J jnl
CoRR
Alexis Jacq, Johan Ferret, Olivier Pietquin, Matthieu Geist
2022 J jnl
CoRR
Paul Muller, Romuald Elie, Mark Rowland, Mathieu Laurière, Julien Pérolat, Sarah Perrin, Matthieu Geist, Georgios Piliouras, Olivier Pietquin, Karl Tuyls
2022 A conf
AAMAS
Paul Muller, Mark Rowland, Romuald Elie, Georgios Piliouras, Julien Pérolat, Mathieu Laurière, Raphaël Marinier, Olivier Pietquin, Karl Tuyls
2022 J jnl
CoRR
Mathieu Laurière, Sarah Perrin, Matthieu Geist, Olivier Pietquin
2022 conf
NAACL-HLT
Alice Martin, Guillaume Quispe, Charles Ollion, Sylvain Le Corff, Florian Strub, Olivier Pietquin
2022 A* conf
AAAI
Shideh Rezaeifar, Robert Dadashi, Nino Vieillard, Léonard Hussenot, Olivier Bachem, Olivier Pietquin, Matthieu Geist
2022 A* conf
ICLR
Mathieu Rita, Florian Strub, Jean-Bastien Grill, Olivier Pietquin, Emmanuel Dupoux
2022 J jnl
CoRR
Mathieu Rita, Florian Strub, Jean-Bastien Grill, Olivier Pietquin, Emmanuel Dupoux
2022 A* conf
ICML
Mathieu Laurière, Sarah Perrin, Sertan Girgin, Paul Muller, Ayush Jain, Theophile Cabannes, Georgios Piliouras, Julien Pérolat, Romuald Elie, Olivier Pietquin, Matthieu Geist
2022 J jnl
CoRR
Mathieu Laurière, Sarah Perrin, Sertan Girgin, Paul Muller, Ayush Jain, Theophile Cabannes, Georgios Piliouras, Julien Pérolat, Romuald Élie, Olivier Pietquin, Matthieu Geist
2022 A conf
AAMAS
Julien Pérolat, Sarah Perrin, Romuald Elie, Mathieu Laurière, Georgios Piliouras, Matthieu Geist, Karl Tuyls, Olivier Pietquin
2022 A conf
AAMAS
Theophile Cabannes, Mathieu Laurière, Julien Pérolat, Raphaël Marinier, Sertan Girgin, Sarah Perrin, Olivier Pietquin, Alexandre M. Bayen, Eric Goubault, Romuald Elie
2022 J jnl
CoRR
Geoffrey Cideron, Sertan Girgin, Anton Raichuk, Olivier Pietquin, Olivier Bachem, Léonard Hussenot
2021 A* conf
ICLR
Yannis Flet-Berliac, Johan Ferret, Olivier Pietquin, Philippe Preux, Matthieu Geist
2021 J jnl
CoRR
Yannis Flet-Berliac, Johan Ferret, Olivier Pietquin, Philippe Preux, Matthieu Geist
2021 J jnl
CoRR
Matthieu Geist, Julien Pérolat, Mathieu Laurière, Romuald Elie, Sarah Perrin, Olivier Bachem, Rémi Munos, Olivier Pietquin
2021 J jnl
CoRR
Robert Dadashi, Léonard Hussenot, Damien Vincent, Sertan Girgin, Anton Raichuk, Matthieu Geist, Olivier Pietquin
2021 A* conf
IJCAI
Mathieu Seurin, Florian Strub, Philippe Preux, Olivier Pietquin
2021 J jnl
CoRR
Mathieu Seurin, Florian Strub, Philippe Preux, Olivier Pietquin
2021 J jnl
CoRR
Sarah Perrin, Mathieu Laurière, Julien Pérolat, Romuald Élie, Matthieu Geist, Olivier Pietquin
2021 A* conf
ICML
Léonard Hussenot, Marcin Andrychowicz, Damien Vincent, Robert Dadashi, Anton Raichuk, Sabela Ramos, Nikola Momchev, Sertan Girgin, Raphaël Marinier, Lukasz Stafiniak, Manu Orsini, Olivier Bachem, Matthieu Geist, Olivier Pietquin
2021 J jnl
CoRR
Léonard Hussenot, Marcin Andrychowicz, Damien Vincent, Robert Dadashi, Anton Raichuk, Lukasz Stafiniak, Sertan Girgin, Raphaël Marinier, Nikola Momchev, Sabela Ramos, Manu Orsini, Olivier Bachem, Matthieu Geist, Olivier Pietquin
2021 J jnl
CoRR
Nino Vieillard, Marcin Andrychowicz, Anton Raichuk, Olivier Pietquin, Matthieu Geist
2021 J jnl
CoRR
Paul Muller, Mark Rowland, Romuald Elie, Georgios Piliouras, Julien Pérolat, Mathieu Laurière, Raphaël Marinier, Olivier Pietquin, Karl Tuyls
2021 Misc conf
ICASSP
Aaqib Saeed, David Grangier, Olivier Pietquin, Neil Zeghidour
2021 J jnl
CoRR
Alice Martin, Guillaume Quispe, Charles Ollion, Sylvain Le Corff, Florian Strub, Olivier Pietquin
2021 A* conf
IJCAI
Sarah Perrin, Mathieu Laurière, Julien Pérolat, Matthieu Geist, Romuald Élie, Olivier Pietquin
2021 J jnl
CoRR
Sarah Perrin, Mathieu Laurière, Julien Pérolat, Matthieu Geist, Romuald Élie, Olivier Pietquin
2021 J jnl
CoRR
Shideh Rezaeifar, Robert Dadashi, Nino Vieillard, Léonard Hussenot, Olivier Bachem, Olivier Pietquin, Matthieu Geist
2021 A* conf
ICML
Robert Dadashi, Shideh Rezaeifar, Nino Vieillard, Léonard Hussenot, Olivier Pietquin, Matthieu Geist
2021 J jnl
CoRR
Robert Dadashi, Shideh Rezaeifar, Nino Vieillard, Léonard Hussenot, Olivier Pietquin, Matthieu Geist
2021 A* conf
ICLR
Robert Dadashi, Léonard Hussenot, Matthieu Geist, Olivier Pietquin
2021 J jnl
CoRR
Sabela Ramos, Sertan Girgin, Léonard Hussenot, Damien Vincent, Hanna Yakubovich, Daniel Toyama, Anita Gergely, Piotr Stanczyk, Raphaël Marinier, Jeremiah Harmsen, Olivier Pietquin, Nikola Momchev
2021 J jnl
CoRR
Julien Pérolat, Sarah Perrin, Romuald Elie, Mathieu Laurière, Georgios Piliouras, Matthieu Geist, Karl Tuyls, Olivier Pietquin
2021 A conf
AAMAS
Johan Ferret, Olivier Pietquin, Matthieu Geist
2021 A conf
AAMAS
Léonard Hussenot, Robert Dadashi, Matthieu Geist, Olivier Pietquin
2021 J jnl
CoRR
Theophile Cabannes, Mathieu Laurière, Julien Pérolat, Raphaël Marinier, Sertan Girgin, Sarah Perrin, Olivier Pietquin, Alexandre M. Bayen, Éric Goubault, Romuald Elie
2021 A* conf
NeurIPS
Nathan Grinsztajn, Johan Ferret, Olivier Pietquin, Philippe Preux, Matthieu Geist
2021 J jnl
CoRR
Nathan Grinsztajn, Johan Ferret, Olivier Pietquin, Philippe Preux, Matthieu Geist
2021 A* conf
NeurIPS
Manu Orsini, Anton Raichuk, Léonard Hussenot, Damien Vincent, Robert Dadashi, Sertan Girgin, Matthieu Geist, Olivier Bachem, Olivier Pietquin, Marcin Andrychowicz
2021 J jnl
CoRR
Manu Orsini, Anton Raichuk, Léonard Hussenot, Damien Vincent, Robert Dadashi, Sertan Girgin, Matthieu Geist, Olivier Bachem, Olivier Pietquin, Marcin Andrychowicz
2021 A* conf
ICLR
Marcin Andrychowicz, Anton Raichuk, Piotr Stanczyk, Manu Orsini, Sertan Girgin, Raphaël Marinier, Léonard Hussenot, Matthieu Geist, Olivier Pietquin, Marcin Michalski, Sylvain Gelly, Olivier Bachem
2020 B conf
IJCNN
Mathieu Seurin, Philippe Preux, Olivier Pietquin
2020 J jnl
CoRR
Mathieu Seurin, Florian Strub, Philippe Preux, Olivier Pietquin
2020 A conf
INTERSPEECH
Mathieu Seurin, Florian Strub, Philippe Preux, Olivier Pietquin
2020 A conf
AAMAS
Léonard Hussenot, Matthieu Geist, Olivier Pietquin
2020 A* conf
ICML
Yuchen Lu, Soumye Singhal, Florian Strub, Aaron C. Courville, Olivier Pietquin
2020 J jnl
CoRR
Yuchen Lu, Soumye Singhal, Florian Strub, Olivier Pietquin, Aaron C. Courville
2020 A* conf
AAAI
Nino Vieillard, Olivier Pietquin, Matthieu Geist
2020 A* conf
NeurIPS
Sarah Perrin, Julien Pérolat, Mathieu Laurière, Matthieu Geist, Romuald Elie, Olivier Pietquin
2020 J jnl
CoRR
Sarah Perrin, Julien Pérolat, Mathieu Laurière, Matthieu Geist, Romuald Elie, Olivier Pietquin
2020 C conf
ACML
Alexis Jacq, Julien Pérolat, Matthieu Geist, Olivier Pietquin
2020 conf
SSCI
Geoffrey Cideron, Mathieu Seurin, Florian Strub, Olivier Pietquin
2020 J jnl
CoRR
Aaqib Saeed, David Grangier, Olivier Pietquin, Neil Zeghidour
2020 A* conf
NeurIPS
Nino Vieillard, Tadashi Kozuno, Bruno Scherrer, Olivier Pietquin, Rémi Munos, Matthieu Geist
2020 J jnl
CoRR
Nino Vieillard, Tadashi Kozuno, Bruno Scherrer, Olivier Pietquin, Rémi Munos, Matthieu Geist
2020 A conf
AISTATS
Nino Vieillard, Bruno Scherrer, Olivier Pietquin, Matthieu Geist
2020 A* conf
NeurIPS
Nino Vieillard, Olivier Pietquin, Matthieu Geist
2020 J jnl
CoRR
Nino Vieillard, Olivier Pietquin, Matthieu Geist
2020 A* conf
AAAI
Romuald Elie, Julien Pérolat, Mathieu Laurière, Matthieu Geist, Olivier Pietquin
2020 J jnl
CoRR
Robert Dadashi, Léonard Hussenot, Matthieu Geist, Olivier Pietquin
2020 B ed.
SIGdial
Olivier Pietquin, Smaranda Muresan, Vivian Chen, Casey Kennington, David Vandyke, Nina Dethlefs, Koji Inoue, Erik Ekstedt, Stefan Ultes
2020 ch.
A Guided Tour of Artificial Intelligence Research (1) (I)
Olivier Buffet, Olivier Pietquin, Paul Weng
2020 J jnl
CoRR
Olivier Buffet, Olivier Pietquin, Paul Weng
2020 A* conf
IJCAI
Johan Ferret, Raphaël Marinier, Matthieu Geist, Olivier Pietquin
2020 J jnl
CoRR
Johan Ferret, Olivier Pietquin, Matthieu Geist
2020 J jnl
CoRR
Léonard Hussenot, Robert Dadashi, Matthieu Geist, Olivier Pietquin
2020 conf
EMNLP (1)
Yuchen Lu, Soumye Singhal, Florian Strub, Olivier Pietquin, Aaron C. Courville
2020 J jnl
CoRR
Yuchen Lu, Soumye Singhal, Florian Strub, Olivier Pietquin, Aaron C. Courville
2020 J jnl
CoRR
Alice Martin, Charles Ollion, Florian Strub, Sylvain Le Corff, Olivier Pietquin
2020 J jnl
CoRR
Marcin Andrychowicz, Anton Raichuk, Piotr Stanczyk, Manu Orsini, Sertan Girgin, Raphaël Marinier, Léonard Hussenot, Matthieu Geist, Olivier Pietquin, Marcin Michalski, Sylvain Gelly, Olivier Bachem
2019 J jnl
CoRR
Mathieu Seurin, Philippe Preux, Olivier Pietquin
2019 A* conf
ICML
Matthieu Geist, Bruno Scherrer, Olivier Pietquin
2019 J jnl
CoRR
Matthieu Geist, Bruno Scherrer, Olivier Pietquin
2019 J jnl
CoRR
Romuald Elie, Julien Pérolat, Mathieu Laurière, Matthieu Geist, Olivier Pietquin
2019 A* conf
NeurIPS
Nicolas Carrara, Edouard Leurent, Romain Laroche, Tanguy Urvoy, Odalric-Ambrym Maillard, Olivier Pietquin
2019 J jnl
CoRR
Johan Ferret, Raphaël Marinier, Matthieu Geist, Olivier Pietquin
2019 J jnl
CoRR
Nino Vieillard, Olivier Pietquin, Matthieu Geist
2019 J jnl
CoRR
Alexis Jacq, Julien Pérolat, Matthieu Geist, Olivier Pietquin
2019 A* conf
ICML
Alexis Jacq, Matthieu Geist, Ana Paiva, Olivier Pietquin
2019 J jnl
CoRR
Lucas Beyer, Damien Vincent, Olivier Teboul, Sylvain Gelly, Matthieu Geist, Olivier Pietquin
2019 J jnl
CoRR
Nino Vieillard, Bruno Scherrer, Olivier Pietquin, Matthieu Geist
2019 A conf
AAMAS
Diana Borsa, Nicolas Heess, Bilal Piot, Siqi Liu, Leonard Hasenclever, Rémi Munos, Olivier Pietquin
2019 J jnl
CoRR
Nino Vieillard, Olivier Pietquin, Matthieu Geist
2019 J jnl
CoRR
Nicolas Carrara, Edouard Leurent, Romain Laroche, Tanguy Urvoy, Odalric-Ambrym Maillard, Olivier Pietquin
2019 J jnl
CoRR
Geoffrey Cideron, Mathieu Seurin, Florian Strub, Olivier Pietquin
2019 conf
ViGIL@NeurIPS
Geoffrey Cideron, Mathieu Seurin, Florian Strub, Olivier Pietquin
2019 J jnl
CoRR
Léonard Hussenot, Matthieu Geist, Olivier Pietquin
2018 A conf
AISTATS
Julien Pérolat, Bilal Piot, Olivier Pietquin
2018 A* conf
AAAI
Todd Hester, Matej Vecerík, Olivier Pietquin, Marc Lanctot, Tom Schaul, Bilal Piot, Dan Horgan, John Quan, Andrew Sendonaris, Ian Osband, Gabriel Dulac-Arnold, John P. Agapiou, Joel Z. Leibo, Audrunas Gruslys
2018 ch.
The Handbook of Multimodal-Multisensor Interfaces, Volume 2 (2)
Gil Keren, Amr El-Desoky Mousa, Olivier Pietquin, Stefanos Zafeiriou, Björn W. Schuller
2018 Misc conf
ICASSP
Alexandre Berard, Laurent Besacier, Ali Can Kocabiyikoglu, Olivier Pietquin
2018 J jnl
CoRR
Alexandre Bérard, Laurent Besacier, Ali Can Kocabiyikoglu, Olivier Pietquin
2018 conf
ICLR (Poster)
Meire Fortunato, Mohammad Gheshlaghi Azar, Bilal Piot, Jacob Menick, Matteo Hessel, Ian Osband, Alex Graves, Volodymyr Mnih, Rémi Munos, Demis Hassabis, Olivier Pietquin, Charles Blundell, Shane Legg
2018 J jnl
CoRR
Tobias Pohlen, Bilal Piot, Todd Hester, Mohammad Gheshlaghi Azar, Dan Horgan, David Budden, Gabriel Barth-Maron, Hado van Hasselt, John Quan, Mel Vecerík, Matteo Hessel, Rémi Munos, Olivier Pietquin
2018 J jnl
CoRR
Julien Pérolat, Mateusz Malinowski, Bilal Piot, Olivier Pietquin
2018 A conf
AAMAS
Merwan Barlier, Romain Laroche, Olivier Pietquin
2018 conf
ECCV (5)
Florian Strub, Mathieu Seurin, Ethan Perez, Harm de Vries, Jérémie Mary, Philippe Preux, Aaron C. Courville, Olivier Pietquin
2018 J jnl
CoRR
Florian Strub, Mathieu Seurin, Ethan Perez, Harm de Vries, Jérémie Mary, Philippe Preux, Aaron C. Courville, Olivier Pietquin
2017 J jnl
IEEE Trans. Neural Networks Learn. Syst.
Bilal Piot, Matthieu Geist, Olivier Pietquin
2017 A* conf
IJCAI
Florian Strub, Harm de Vries, Jérémie Mary, Bilal Piot, Aaron C. Courville, Olivier Pietquin
2017 J jnl
CoRR
Florian Strub, Harm de Vries, Jérémie Mary, Bilal Piot, Aaron C. Courville, Olivier Pietquin
2017 A* conf
CVPR
Harm de Vries, Florian Strub, Sarath Chandar, Olivier Pietquin, Hugo Larochelle, Aaron C. Courville
2017 conf
NIPS
Matthieu Geist, Bilal Piot, Olivier Pietquin
2017 conf
WMT
Alexandre Berard, Laurent Besacier, Olivier Pietquin
2017 J jnl
CoRR
Alexandre Berard, Olivier Pietquin, Laurent Besacier
2017 A conf
AISTATS
Julien Pérolat, Florian Strub, Bilal Piot, Olivier Pietquin
2017 J jnl
CoRR
Todd Hester, Matej Vecerík, Olivier Pietquin, Marc Lanctot, Tom Schaul, Bilal Piot, Andrew Sendonaris, Gabriel Dulac-Arnold, Ian Osband, John P. Agapiou, Joel Z. Leibo, Audrunas Gruslys
2017 J jnl
CoRR
Matej Vecerík, Todd Hester, Jonathan Scholz, Fumin Wang, Olivier Pietquin, Bilal Piot, Nicolas Heess, Thomas Rothörl, Thomas Lampe, Martin A. Riedmiller
2017 conf
NIPS
Harm de Vries, Florian Strub, Jérémie Mary, Hugo Larochelle, Olivier Pietquin, Aaron C. Courville
2017 J jnl
CoRR
Harm de Vries, Florian Strub, Jérémie Mary, Hugo Larochelle, Olivier Pietquin, Aaron C. Courville
2017 J jnl
CoRR
Meire Fortunato, Mohammad Gheshlaghi Azar, Bilal Piot, Jacob Menick, Ian Osband, Alex Graves, Vlad Mnih, Rémi Munos, Demis Hassabis, Olivier Pietquin, Charles Blundell, Shane Legg
2017 J jnl
CoRR
Diana Borsa, Bilal Piot, Rémi Munos, Olivier Pietquin
2016 A conf
INTERSPEECH
Merwan Barlier, Romain Laroche, Olivier Pietquin
2016 conf
IWSDS
Layla El Asri, Romain Laroche, Olivier Pietquin
2016 J jnl
CoRR
Bilal Piot, Matthieu Geist, Olivier Pietquin
2016 J jnl
CoRR
Harm de Vries, Florian Strub, Sarath Chandar, Olivier Pietquin, Hugo Larochelle, Aaron C. Courville
2016 ch.
Toward Robotic Socially Believable Behaving Systems (I)
Stéphane Dupont, Hüseyin Çakmak, William Curran, Thierry Dutoit, Jennifer Hofmann, Gary McKeown, Olivier Pietquin, Tracey Platt, Willibald Ruch, Jérôme Urbain
2016 J jnl
CoRR
Julien Pérolat, Florian Strub, Bilal Piot, Olivier Pietquin
2016 conf
SLT
Merwan Barlier, Romain Laroche, Olivier Pietquin
2016 J jnl
CoRR
Alexandre Berard, Olivier Pietquin, Christophe Servan, Laurent Besacier
2016 B conf
LREC
Alexandre Berard, Christophe Servan, Olivier Pietquin, Laurent Besacier
2016 A conf
AISTATS
Julien Pérolat, Bilal Piot, Bruno Scherrer, Olivier Pietquin
2016 A* conf
ICML
Hadrien Glaude, Olivier Pietquin
2016 A conf
AAMAS
Layla El Asri, Bilal Piot, Matthieu Geist, Romain Laroche, Olivier Pietquin
2016 J jnl
CoRR
Matthieu Geist, Bilal Piot, Olivier Pietquin
2016 A* conf
ICML
Julien Pérolat, Bilal Piot, Matthieu Geist, Bruno Scherrer, Olivier Pietquin
2015 A* conf
ICML
Julien Pérolat, Bruno Scherrer, Bilal Piot, Olivier Pietquin
2015 conf
SSCI
Timothé Collet, Olivier Pietquin
2015 conf
SIGDIAL Conference
Merwan Barlier, Julien Pérolat, Romain Laroche, Olivier Pietquin
2015 conf
MLIS@ICML
Bilal Piot, Olivier Pietquin, Matthieu Geist
2015 A* conf
IJCAI
Thibaut Munzer, Bilal Piot, Matthieu Geist, Olivier Pietquin, Manuel Lopes
2015 conf
MLSP
Hadrien Glaude, Cyrille Enderli, Jean-François Grandin, Olivier Pietquin
2015 conf
ICONIP (2)
Hadrien Glaude, Cyrille Enderli, Olivier Pietquin
2015 conf
ICONIP (2)
Timothé Collet, Olivier Pietquin
2015 J jnl
Comput. Intell. Neurosci.
Timothé Collet, Olivier Pietquin
2015 conf
MLIS@ICML
Heriberto Cuayáhuitl, Nina Dethlefs, Lutz Frommberger, Martijn van Otterlo, Olivier Pietquin
2015 C conf
ASRU
Hadrien Glaude, Cyrille Enderli, Olivier Pietquin
2014 conf
ADPRL
Timothé Collet, Olivier Pietquin
2014 conf
ECML/PKDD (2)
Bilal Piot, Matthieu Geist, Olivier Pietquin
2014 A conf
AAMAS
Bilal Piot, Matthieu Geist, Olivier Pietquin
2014 B conf
LREC
Layla El Asri, Romain Laroche, Olivier Pietquin
2014 conf
NIPS
Bilal Piot, Matthieu Geist, Olivier Pietquin
2014 J jnl
CoRR
Matthieu Geist, Olivier Pietquin
2014 B conf
LREC
Layla El Asri, Rémi Lemonnier, Romain Laroche, Olivier Pietquin, Hatim Khouzaimi
2014 Misc conf
ICASSP
Layla El Asri, Hatim Khouzaimi, Romain Laroche, Olivier Pietquin
2014 A conf
INTERSPEECH
Bilal Piot, Olivier Pietquin, Matthieu Geist
2014 conf
ADPRL
Hadrien Glaude, Olivier Pietquin, Cyrille Enderli
2013 conf
ECML/PKDD (1)
Edouard Klein, Bilal Piot, Matthieu Geist, Olivier Pietquin
2013 J jnl
Knowl. Eng. Rev.
Olivier Pietquin, Helen F. Hastie
2013 J jnl
IEEE Trans. Neural Networks Learn. Syst.
Matthieu Geist, Olivier Pietquin
2013 J jnl
Rev. d'Intelligence Artif.
Edouard Klein, Bilal Piot, Matthieu Geist, Olivier Pietquin
2013 conf
MLIS@IJCAI
Olivier Pietquin
2013 conf
eNTERFACE
Maurizio Mancini, Laurent Ach, Emeline Bantegnie, Tobias Baur, Nadia Berthouze, Debajyoti Datta, Yu Ding, Stéphane Dupont, Harry J. Griffin, Florian Lingenfelser, Radoslaw Niewiadomski, Catherine Pelachaud, Olivier Pietquin, Bilal Piot, Jérôme Urbain, Gualtiero Volpe, Johannes Wagner
2013 A conf
AAMAS
Radoslaw Niewiadomski, Jennifer Hofmann, Jérôme Urbain, Tracey Platt, Johannes Wagner, Bilal Piot, Hüseyin Çakmak, Sathish Pammi, Tobias Baur, Stéphane Dupont, Matthieu Geist, Florian Lingenfelser, Gary McKeown, Olivier Pietquin, Willibald Ruch
2013 conf
ECML/PKDD (1)
Bilal Piot, Matthieu Geist, Olivier Pietquin
2013 conf
SIGDIAL Conference
Lucie Daubigney, Matthieu Geist, Olivier Pietquin
2013 A conf
INTERSPEECH
Lucie Daubigney, Matthieu Geist, Olivier Pietquin
2013 Misc conf
ICASSP
Lucie Daubigney, Matthieu Geist, Olivier Pietquin
2013 conf
SLSP
Layla El Asri, Romain Laroche, Olivier Pietquin
2012 J jnl
IEEE J. Sel. Top. Signal Process.
Lucie Daubigney, Matthieu Geist, Senthilkumar Chandramohan, Olivier Pietquin
2012 A conf
ECAI
Olivier Pietquin, Fabio Tango
2012 conf
ITG Conference on Speech Communication
Senthilkumar Chandramohan, Matthieu Geist, Fabrice Lefèvre, Olivier Pietquin
2012 Misc conf
ICASSP
Senthilkumar Chandramohan, Matthieu Geist, Fabrice Lefèvre, Olivier Pietquin
2012 conf
IWSDS
Senthilkumar Chandramohan, Matthieu Geist, Fabrice Lefèvre, Olivier Pietquin
2012 J jnl
IEEE J. Sel. Top. Signal Process.
Jason D. Williams, Kai Yu, Brahim Chaib-draa, Oliver Lemon, Roberto Pieraccini, Olivier Pietquin, Pascal Poupart, Steve J. Young
2012 conf
NIPS
Edouard Klein, Matthieu Geist, Bilal Piot, Olivier Pietquin
2012 Misc conf
ICASSP
Lucie Daubigney, Matthieu Geist, Olivier Pietquin
2012 conf
JEP-TALN-RECITAL 2012
Lucie Daubigney, Matthieu Geist, Olivier Pietquin
2012 conf
STAIRS
Layla El Asri, Romain Laroche, Olivier Pietquin
2012 conf
SDCTD@NAACL-HLT
Olivier Pietquin
2011 conf
ICMLA (1)
Hadrien Glaude, Fadi Akrimi, Matthieu Geist, Olivier Pietquin
2011 conf
HCI (17)
Fabio Tango, Luca Minin, Raghav Aras, Olivier Pietquin
2011 conf
CIVTS
Olivier Pietquin, Fabio Tango, Raghav Aras
2011 conf
EWRL
Edouard Klein, Matthieu Geist, Olivier Pietquin
2011 book
Olivier Pietquin
2011 conf
CCMB
Jérémy Fix, Matthieu Geist, Olivier Pietquin, Hervé Frezza-Buet
2011 J jnl
Neural Process. Lett.
Beatrice Chevaillier, Damien Mandry, Jean-Luc Collette, Michel Claudon, Marie-Agnès Galloy, Olivier Pietquin
2011 J jnl
ACM Trans. Speech Lang. Process.
Oliver Lemon, Olivier Pietquin
2011 conf
Active Learning and Experimental Design @ AISTATS
Matthieu Geist, Olivier Pietquin
2011 conf
SLaTE
Olivier Pietquin, Lucie Daubigney, Matthieu Geist
2011 conf
ADPRL
Matthieu Geist, Olivier Pietquin
2011 A* conf
IJCAI
Olivier Pietquin, Matthieu Geist, Senthilkumar Chandramohan
2011 J jnl
ACM Trans. Speech Lang. Process.
Olivier Pietquin, Matthieu Geist, Senthilkumar Chandramohan, Hervé Frezza-Buet
2011 B conf
ESANN
Lucie Daubigney, Olivier Pietquin
2011 B conf
IJCNLP
Stéphane Rossignol, Olivier Pietquin, Michel Ianotto
2011 A conf
INTERSPEECH
Lucie Daubigney, Milica Gasic, Senthilkumar Chandramohan, Matthieu Geist, Olivier Pietquin, Steve J. Young
2011 A conf
INTERSPEECH
Senthilkumar Chandramohan, Matthieu Geist, Fabrice Lefèvre, Olivier Pietquin
2010 Misc conf
ICASSP
Julien Oster, Olivier Pietquin, Michel Kraemer, Jacques Felblinger
2010 J jnl
Rev. d'Intelligence Artif.
Matthieu Geist, Olivier Pietquin, Gabriel Fricout
2010 conf
ICUMT
Matthieu Geist, Olivier Pietquin
2010 J jnl
J. Artif. Intell. Res.
Matthieu Geist, Olivier Pietquin
2010 J jnl
IEEE Trans. Biomed. Eng.
Julien Oster, Olivier Pietquin, Michel Kraemer, Jacques Felblinger
2010 conf
EUSIPCO
Beatrice Chevaillier, Jean-Luc Collette, Damien Mandry, Michel Claudon, Olivier Pietquin
2010 B conf
ESANN
Jean-Louis Gutzwiller, Hervé Frezza-Buet, Olivier Pietquin
2010 A conf
INTERSPEECH
Senthilkumar Chandramohan, Matthieu Geist, Olivier Pietquin
2010 B conf
MDAI
Matthieu Geist, Olivier Pietquin
2010 conf
IWSDS
Stéphane Rossignol, Olivier Pietquin, Michel Ianotto
2010 A conf
INTERSPEECH
Stéphane Rossignol, Olivier Pietquin
2010 conf
SIGDIAL Conference
Senthilkumar Chandramohan, Matthieu Geist, Olivier Pietquin
2010 conf
ICUMT
Matthieu Geist, Olivier Pietquin
2010 conf
IWSDS
Senthilkumar Chandramohan, Olivier Pietquin
2009 Misc conf
ICASSP
Julien Oster, Olivier Pietquin, Roger Abächerli, Michel Kraemer, Jacques Felblinger
2009 conf
ADPRL
Matthieu Geist, Olivier Pietquin, Gabriel Fricout
2009 B conf
ESANN
Matthieu Geist, Olivier Pietquin, Gabriel Fricout
2009 conf
ICONIP (1)
Matthieu Geist, Olivier Pietquin, Gabriel Fricout
2008 Misc conf
ICASSP
Julien Oster, Olivier Pietquin, Gilles Bosser
2008 conf
EWRL
Matthieu Geist, Olivier Pietquin, Gabriel Fricout
2008 conf
EUSIPCO
Beatrice Chevaillier, Damien Mandry, Yannick Ponvianne, Jean-Luc Collette, Michel Claudon, Olivier Pietquin
2008 Misc conf
ICASSP
Beatrice Chevaillier, Yannick Ponvianne, Jean-Luc Collette, Damien Mandry, Michel Claudon, Olivier Pietquin
2007 conf
ICASSP (4)
Olivier Pietquin
2007 A conf
INTERSPEECH
Oliver Lemon, Olivier Pietquin
2006 J jnl
IEEE Trans. Speech Audio Process.
Olivier Pietquin, Thierry Dutoit
2006 A conf
ICME
Olivier Pietquin
2006 conf
ICASSP (1)
Olivier Pietquin, Thierry Dutoit
2006 Misc conf
AIMSA
Olivier Pietquin
2005 A conf
ICME
Olivier Pietquin
2005 A conf
INTERSPEECH
Olivier Pietquin, Richard Beaufort
2005 conf
TALN (Articles courts)
Olivier Pietquin
2004 conf
IHM
Olivier Pietquin
2003 A conf
ICME
Olivier Pietquin, Thierry Dutoit
2002 Misc conf
ICASSP
Olivier Pietquin, Steve Renals
APK_FEATURES_PDD-Tech_Annex.md
← Index APK_FEATURES_PDD-Tech_Annex.md markdown
# APK Extractor — Technical Annex

**Companion to:** APK_FEATURES_PDD.md
**Audience:** Engineers implementing the APK extractors
**Date:** 2026-02-21

---

## Table of Contents

1. [File Structure](#1-file-structure)
2. [Dependencies Setup](#2-dependencies-setup)
3. [Base Class: APKExtractor](#3-base-class-apkextractor)
4. [Dataclass Definitions](#4-dataclass-definitions)
5. [Tag Enum Updates](#5-tag-enum-updates)
6. [Extractor Implementation Details](#6-extractor-implementation-details)
7. [Ingestor Integration](#7-ingestor-integration)
8. [Hashes Dataclass Update](#8-hashes-dataclass-update)
9. [ClickHouse Schema](#9-clickhouse-schema)
10. [Androguard API Reference](#10-androguard-api-reference)
11. [Known Packer/Protector Signatures](#11-known-packerprotector-signatures)
12. [Sensitive API Categorization Reference](#12-sensitive-api-categorization-reference)

---

## 1. File Structure

Create the following files:

```
redb/extractors/
├── apk_extractor.py                          # APKExtractor base class
├── apk_extractors/
│   ├── __init__.py
│   ├── apk_features.py                       # APKFeaturesExtractor
│   ├── apk_manifest.py                       # APKManifestExtractor
│   ├── apk_permissions.py                    # APKPermissionsExtractor
│   ├── apk_signature.py                      # APKSignatureExtractor
│   ├── apk_dex.py                            # APKDexExtractor
│   ├── apk_resources.py                      # APKResourceExtractor
│   ├── apk_native_libs.py                    # APKNativeLibExtractor
│   └── apk_inconsistency_tests.py            # APKInconsistencyTestsExtractor
```

Modified files:

```
redb/extractors/enum.py                       # Add APK tags
redb/models/dataclasses.py                    # Add APK dataclasses + permhash field in Hashes
redb/ingestor.py                              # Wire up APK dispatch
requirements.txt                              # Add androguard, permhash
```

---

## 2. Dependencies Setup

Add to `requirements.txt`:

```
androguard>=4.1
permhash
```

Install and verify:

```bash
pip install androguard permhash
python -c "from androguard.core.apk import APK; print('androguard OK')"
python -c "import permhash; print('permhash OK')"
```

---

## 3. Base Class: APKExtractor

**File:** `redb/extractors/apk_extractor.py`

Follow the exact pattern of `PEExtractor` (`redb/extractors/pe_extractor.py`) and `MachOExtractor` (`redb/extractors/macho_extractor.py`).

```python
import logging
from abc import ABCMeta, abstractmethod
import zipfile

from androguard.core.apk import APK

from redb.extractors.extractor import Extractor

logger = logging.getLogger(__name__)


@abstractmethod
class APKExtractor(Extractor, metaclass=ABCMeta):

    def __init__(
        self,
        filepath,
        log,
        exporters=None,
        index_prefix=None,
        elastic_index=None,
        known_benign=False,
        known_malicious=False,
        apk=None,
    ):
        super().__init__(
            filepath,
            log,
            exporters,
            index_prefix,
            elastic_index,
            known_benign,
            known_malicious
        )
        self.apk = apk if apk else self._generate_apk_object()

    def _generate_apk_object(self):
        """Parse APK using androguard."""
        apk = None
        try:
            apk = APK(self.filepath)
            if not apk.is_valid_APK():
                self.log.warning(
                    f"APK validation warning for {self.hash.sha256}"
                )
                # Still return the object — partial parsing may still work
        except Exception as e:
            self.log.error(
                f"Format error parsing APK {self.hash.sha256}: {e}"
            )
        return apk

    def _is_valid_apk(self):
        """Check if the APK object was parsed successfully."""
        return self.apk is not None

    def _get_zip_file(self):
        """Get a zipfile.ZipFile handle for direct archive inspection."""
        try:
            return zipfile.ZipFile(self.filepath, 'r')
        except (zipfile.BadZipFile, Exception) as e:
            self.log.error(f"Failed to open APK as ZIP: {e}")
            return None

    def _list_files(self):
        """List all files in the APK archive."""
        if not self._is_valid_apk():
            return []
        try:
            return self.apk.get_files()
        except Exception as e:
            self.log.error(f"Error listing APK files: {e}")
            return []
```

**Key design decisions:**
- The `apk=` parameter allows the ingestor to parse once and share across all APK extractors (same pattern as `pe=` in PEExtractor, `macho=` in MachOExtractor, `elf=` in ELFExtractor)
- `_get_zip_file()` provides direct ZIP access for extractors that need it (resources, native libs, inconsistency tests)
- The androguard `APK` object is the primary parsing interface; `zipfile` is secondary for archive-level inspection

---

## 4. Dataclass Definitions

**File:** `redb/models/dataclasses.py`

Add after the Mach-O dataclasses section. Follow the exact style of existing dataclasses (type annotations, `Optional` for nullable fields, `field(default_factory=list)` for list defaults).

```python
# ============================================================================
# APK Dataclasses
# ============================================================================

@dataclass
class APKFeatures:
    """Core APK metadata and properties."""
    package_name: str
    app_name: str
    version_code: int
    version_name: str
    min_sdk_version: Optional[int] = None
    target_sdk_version: Optional[int] = None
    compile_sdk_version: Optional[int] = None
    main_activity: Optional[str] = None
    is_debuggable: bool = False
    allow_backup: bool = True
    uses_cleartext_traffic: bool = False
    supported_abis: List[str] = field(default_factory=list)
    dex_count: int = 0
    total_dex_size: int = 0
    total_file_count: int = 0
    has_native_code: bool = False
    has_assets: bool = False
    uses_libraries: List[str] = field(default_factory=list)
    earliest_content_modification: Optional[str] = None  # ISO 8601
    latest_content_modification: Optional[str] = None    # ISO 8601
    contains_embedded_apk: bool = False


@dataclass
class APKManifestComponent:
    """Single Android component (activity, service, receiver, provider)."""
    component_type: str      # "activity", "service", "receiver", "provider"
    class_name: str
    is_exported: bool
    intent_actions: List[str] = field(default_factory=list)
    intent_categories: List[str] = field(default_factory=list)


@dataclass
class APKManifest:
    """Full AndroidManifest.xml analysis."""
    activity_count: int
    service_count: int
    receiver_count: int
    provider_count: int
    activities: List[str] = field(default_factory=list)
    services: List[str] = field(default_factory=list)
    receivers: List[str] = field(default_factory=list)
    providers: List[str] = field(default_factory=list)
    exported_components: List[str] = field(default_factory=list)
    intent_filters_by_action: List[str] = field(default_factory=list)
    intent_filters_by_category: List[str] = field(default_factory=list)
    uses_features: List[str] = field(default_factory=list)
    meta_data: Optional[Dict] = None
    manifest_xml: Optional[str] = None  # Full decompiled XML text


@dataclass
class APKPermission:
    """Single permission entry for ClickHouse export."""
    permission_name: str
    protection_level: str    # "normal", "dangerous", "signature", "signatureOrSystem", "unknown"
    is_custom: bool = False  # True if declared by the app itself


@dataclass
class APKPermissions:
    """APK permission summary."""
    total_permission_count: int
    dangerous_permission_count: int
    permissions: List[str] = field(default_factory=list)
    dangerous_permissions: List[str] = field(default_factory=list)
    custom_permissions: List[str] = field(default_factory=list)
    permission_details: List[APKPermission] = field(default_factory=list)
    permhash: Optional[str] = None


@dataclass
class APKCertificate:
    """X.509 certificate from APK signature."""
    subject: str
    issuer: str
    serial_number: str
    valid_from: str
    valid_to: str
    thumbprint_sha1: str
    thumbprint_sha256: str
    algorithm: Optional[str] = None
    key_size: Optional[int] = None
    is_self_signed: bool = False


@dataclass
class APKCodeSigningInfo:
    """Complete APK signing information."""
    _id: str  # sha256
    is_signed: bool
    signature_scheme_versions: List[int] = field(default_factory=list)  # [1], [1,2], [1,2,3], etc.
    number_of_certificates: int = 0
    x509_certificates: Optional[List[APKCertificate]] = None
    signer_subject: Optional[str] = None
    signer_issuer: Optional[str] = None


@dataclass
class APKDexFile:
    """Analysis of a single DEX file."""
    filename: str
    sha256: str
    class_count: int
    method_count: int
    string_count: int
    top_packages: Optional[List[Dict]] = None  # [{"package": str, "class_count": int}]
    api_usage: Optional[Dict[str, List[str]]] = None  # {"reflection": [...], "crypto": [...], ...}
    obfuscation_indicators: Optional[Dict] = None


@dataclass
class APKResource:
    """Embedded resource file entry."""
    path: str
    size: int
    sha256: str
    filetype_magika: str
    is_suspicious: bool = False  # True for executable types


@dataclass
class APKNativeLib:
    """Native .so library entry."""
    abi: str          # e.g., "arm64-v8a"
    filename: str     # e.g., "libfoo.so"
    size: int
    sha256: str
    is_known_packer: bool = False  # True if matches known packer lib name


@dataclass
class APKInconsistencyTests:
    """APK anomaly and anti-analysis detection results."""
    test_zip_bomb: Optional[bool] = None
    test_zip_duplicate_entries: Optional[bool] = None
    test_zip_path_traversal: Optional[bool] = None
    test_zip_suspicious_timestamps: Optional[bool] = None
    test_hidden_dex_files: Optional[bool] = None
    test_manifest_component_mismatch: Optional[bool] = None
    test_debuggable_release: Optional[bool] = None
    test_emulator_detection_strings: Optional[bool] = None
    test_debugger_detection: Optional[bool] = None
    test_root_detection: Optional[bool] = None
```

---

## 5. Tag Enum Updates

**File:** `redb/extractors/enum.py`

Add at the end of the `Tag` class, after the ELF section:

```python
    # APK
    APK_FEATURES = "apk_features"
    APK_MANIFEST = "apk_manifest"
    APK_PERMISSIONS = "apk_permissions"
    APK_SIGNATURE = "apk_signature"
    APK_DEX = "apk_dex"
    APK_RESOURCES = "apk_resources"
    APK_NATIVE_LIBS = "apk_native_libs"
    APK_INCONSISTENCY_TESTS = "apk_inconsistency_tests"
```

---

## 6. Extractor Implementation Details

### 6.1 APKFeaturesExtractor

**File:** `redb/extractors/apk_extractors/apk_features.py`

```python
import inspect
import zipfile
from datetime import datetime, timezone
from typing import Any

from redb.extractors.enum import Tag
from redb.extractors.apk_extractor import APKExtractor
from redb.models.dataclasses import APKFeatures


class APKFeaturesExtractor(APKExtractor):

    def __init__(
        self, filepath, log, exporters=None, index_prefix=None,
        elastic_index=None, known_benign=False, known_malicious=False,
        apk=None,
    ):
        super().__init__(
            filepath, log, exporters, index_prefix,
            elastic_index, known_benign, known_malicious, apk,
        )
        self.apk_features = None
        self.elastic_index = self.index_prefix + "-apk_features"

    def tag(self):
        return Tag.APK_FEATURES.value

    def _extract_zip_timestamps(self):
        """Extract earliest and latest content modification from ZIP entries."""
        # Use zipfile directly for this — androguard doesn't expose ZIP metadata
        earliest = None
        latest = None
        try:
            zf = self._get_zip_file()
            if zf:
                with zf:
                    for info in zf.infolist():
                        try:
                            # date_time is (year, month, day, hour, minute, second)
                            dt = datetime(*info.date_time)
                            if earliest is None or dt < earliest:
                                earliest = dt
                            if latest is None or dt > latest:
                                latest = dt
                        except (ValueError, TypeError):
                            continue
        except Exception as e:
            self.log.warning(f"Error extracting ZIP timestamps: {e}")
        return (
            earliest.isoformat() if earliest else None,
            latest.isoformat() if latest else None,
        )

    def _extract_supported_abis(self):
        """Determine supported ABIs from lib/ directory."""
        abis = set()
        for f in self._list_files():
            if f.startswith("lib/") and f.endswith(".so"):
                parts = f.split("/")
                if len(parts) >= 3:
                    abis.add(parts[1])
        return sorted(abis)

    def _count_dex_files(self):
        """Count DEX files and compute total size."""
        dex_count = 0
        total_size = 0
        try:
            zf = self._get_zip_file()
            if zf:
                with zf:
                    for info in zf.infolist():
                        if info.filename.endswith(".dex"):
                            dex_count += 1
                            total_size += info.file_size
        except Exception as e:
            self.log.warning(f"Error counting DEX files: {e}")
        return dex_count, total_size

    def _check_embedded_apk(self):
        """Check if the archive contains nested APK files."""
        for f in self._list_files():
            if f.lower().endswith(".apk"):
                return True
        return False

    def extract(self):
        try:
            if not self._is_valid_apk():
                self.log.error(f"Invalid APK for {self.hash.sha256}")
                return None

            # Core metadata from androguard
            package_name = self.apk.get_package() or ""
            app_name = self.apk.get_app_name() or ""

            # version_code may be string or int
            try:
                version_code = int(self.apk.get_androidversion_code() or 0)
            except (ValueError, TypeError):
                version_code = 0

            version_name = self.apk.get_androidversion_name() or ""

            # SDK versions
            min_sdk = self.apk.get_min_sdk_version()
            target_sdk = self.apk.get_target_sdk_version()
            # NOTE: compile_sdk may not be available in all androguard versions
            compile_sdk = None
            try:
                compile_sdk = self.apk.get_effective_target_sdk_version()
            except AttributeError:
                pass

            min_sdk = int(min_sdk) if min_sdk else None
            target_sdk = int(target_sdk) if target_sdk else None
            compile_sdk = int(compile_sdk) if compile_sdk else None

            # Main activity
            main_activity = self.apk.get_main_activity()

            # Flags from manifest
            # androguard provides get_attribute_value for manifest attributes
            is_debuggable = self.apk.get_attribute_value(
                "application", "debuggable"
            ) == "true"
            allow_backup = self.apk.get_attribute_value(
                "application", "allowBackup"
            ) != "false"  # default is true
            uses_cleartext = self.apk.get_attribute_value(
                "application", "usesCleartextTraffic"
            ) == "true"

            # Archive-level analysis
            supported_abis = self._extract_supported_abis()
            dex_count, total_dex_size = self._count_dex_files()
            all_files = self._list_files()
            total_file_count = len(all_files)
            has_native_code = any(
                f.startswith("lib/") and f.endswith(".so") for f in all_files
            )
            has_assets = any(f.startswith("assets/") for f in all_files)
            contains_embedded_apk = self._check_embedded_apk()

            # Uses-library
            uses_libraries = []
            try:
                libs = self.apk.get_libraries()
                uses_libraries = list(libs) if libs else []
            except Exception:
                pass

            # ZIP timestamps
            earliest_mod, latest_mod = self._extract_zip_timestamps()

            self.apk_features = APKFeatures(
                package_name=package_name,
                app_name=app_name,
                version_code=version_code,
                version_name=version_name,
                min_sdk_version=min_sdk,
                target_sdk_version=target_sdk,
                compile_sdk_version=compile_sdk,
                main_activity=main_activity,
                is_debuggable=is_debuggable,
                allow_backup=allow_backup,
                uses_cleartext_traffic=uses_cleartext,
                supported_abis=supported_abis,
                dex_count=dex_count,
                total_dex_size=total_dex_size,
                total_file_count=total_file_count,
                has_native_code=has_native_code,
                has_assets=has_assets,
                uses_libraries=uses_libraries,
                earliest_content_modification=earliest_mod,
                latest_content_modification=latest_mod,
                contains_embedded_apk=contains_embedded_apk,
            )
            return self.apk_features

        except Exception as e:
            self.log.error(
                f"Error extracting APK features {self.hash.sha256}: {e}"
            )
            return None

    def prepare_export_data(self, exporter_type: str) -> Any:
        if exporter_type == "ElasticsearchExporter":
            return self.apk_features
        elif exporter_type == "ClickHouseExporter":
            if not self.apk_features:
                return None

            f = self.apk_features
            data = [[
                self.sha256, self.md5, self.sha1,
                f.package_name,
                f.app_name,
                f.version_code,
                f.version_name,
                f.min_sdk_version,
                f.target_sdk_version,
                f.compile_sdk_version,
                f.main_activity,
                int(f.is_debuggable),
                int(f.allow_backup),
                int(f.uses_cleartext_traffic),
                f.supported_abis,
                f.dex_count,
                f.total_dex_size,
                f.total_file_count,
                int(f.has_native_code),
                int(f.has_assets),
                f.uses_libraries,
                f.earliest_content_modification,
                f.latest_content_modification,
                int(f.contains_embedded_apk),
                datetime.now(timezone.utc),
            ]]

            column_names = [
                "sha256", "md5", "sha1",
                "package_name", "app_name", "version_code", "version_name",
                "min_sdk_version", "target_sdk_version", "compile_sdk_version",
                "main_activity",
                "is_debuggable", "allow_backup", "uses_cleartext_traffic",
                "supported_abis",
                "dex_count", "total_dex_size", "total_file_count",
                "has_native_code", "has_assets",
                "uses_libraries",
                "earliest_content_modification", "latest_content_modification",
                "contains_embedded_apk",
                "analysis_date",
            ]

            column_type_names = [
                "FixedString(64)", "FixedString(32)", "FixedString(40)",
                "String", "String", "UInt32", "String",
                "Nullable(UInt16)", "Nullable(UInt16)", "Nullable(UInt16)",
                "Nullable(String)",
                "UInt8", "UInt8", "UInt8",
                "Array(String)",
                "UInt16", "UInt64", "UInt32",
                "UInt8", "UInt8",
                "Array(String)",
                "Nullable(String)", "Nullable(String)",
                "UInt8",
                "DateTime64(3, 'UTC')",
            ]

            return (data, column_names, column_type_names)

    def get_clickhouse_table(self) -> str:
        return "redb_apk_features"
```

### 6.2 APKManifestExtractor

**File:** `redb/extractors/apk_extractors/apk_manifest.py`

**Key androguard API calls:**
```python
# Activities, services, receivers, providers
self.apk.get_activities()       # Returns list of activity class names
self.apk.get_services()         # Returns list of service class names
self.apk.get_receivers()        # Returns list of receiver class names
self.apk.get_providers()        # Returns list of provider class names

# Exported check (per component)
self.apk.get_intent_filters(component_type, component_name)
# Returns dict: {"action": [...], "category": [...]}

# Uses-features
self.apk.get_features()         # Returns list of feature strings

# Full XML
self.apk.get_android_manifest_xml().toxml()
# OR
self.apk.get_android_manifest_axml().get_xml()
```

**Implementation notes:**
- For ClickHouse export of components, use a **one-row-per-component** table (`redb_apk_components`) with columns: `sha256`, `component_type`, `class_name`, `is_exported`, `intent_actions` (Array), `intent_categories` (Array), `analysis_date`
- For the aggregated manifest data (counts, feature list, full XML), use a **one-row-per-APK** table (`redb_apk_manifest`)
- To determine if a component is exported: check `android:exported` attribute. If not explicitly set, it's implicitly exported if the component has intent filters (Android default behavior pre-API 31). From API 31+, `android:exported` must be explicit

### 6.3 APKPermissionsExtractor

**File:** `redb/extractors/apk_extractors/apk_permissions.py`

**Key androguard API calls:**
```python
# Requested permissions
self.apk.get_permissions()              # Returns list of permission strings
self.apk.get_declared_permissions()     # Custom permissions defined by the app

# For protection level, use androguard's permission mapping:
from androguard.core.api_specific_resources import load_permission_mappings
permission_map = load_permission_mappings(target_sdk)
# permission_map[perm_name] -> {"protectionLevel": "dangerous", ...}
```

**Permhash computation:**
```python
import permhash
ph = permhash.permhash_apk(self.filepath)
# Returns SHA-256 hex string
```

**Known dangerous permissions** (reference list for classification fallback):
```python
DANGEROUS_PERMISSIONS = {
    "android.permission.READ_CALENDAR",
    "android.permission.WRITE_CALENDAR",
    "android.permission.CAMERA",
    "android.permission.READ_CONTACTS",
    "android.permission.WRITE_CONTACTS",
    "android.permission.GET_ACCOUNTS",
    "android.permission.ACCESS_FINE_LOCATION",
    "android.permission.ACCESS_COARSE_LOCATION",
    "android.permission.ACCESS_BACKGROUND_LOCATION",
    "android.permission.RECORD_AUDIO",
    "android.permission.READ_PHONE_STATE",
    "android.permission.READ_PHONE_NUMBERS",
    "android.permission.CALL_PHONE",
    "android.permission.ANSWER_PHONE_CALLS",
    "android.permission.ADD_VOICEMAIL",
    "android.permission.USE_SIP",
    "android.permission.BODY_SENSORS",
    "android.permission.SEND_SMS",
    "android.permission.RECEIVE_SMS",
    "android.permission.READ_SMS",
    "android.permission.RECEIVE_WAP_PUSH",
    "android.permission.RECEIVE_MMS",
    "android.permission.READ_EXTERNAL_STORAGE",
    "android.permission.WRITE_EXTERNAL_STORAGE",
    "android.permission.READ_MEDIA_IMAGES",
    "android.permission.READ_MEDIA_VIDEO",
    "android.permission.READ_MEDIA_AUDIO",
    "android.permission.POST_NOTIFICATIONS",
    "android.permission.NEARBY_WIFI_DEVICES",
    "android.permission.ACTIVITY_RECOGNITION",
    "android.permission.BLUETOOTH_SCAN",
    "android.permission.BLUETOOTH_ADVERTISE",
    "android.permission.BLUETOOTH_CONNECT",
}
```

**ClickHouse export:** One row per permission per APK in `redb_apk_permissions`:
- `sha256`, `permission_name`, `protection_level`, `is_custom`, `analysis_date`

The `permhash` value is also stored separately — see Section 8 for integration with `HashExtractor`.

### 6.4 APKSignatureExtractor

**File:** `redb/extractors/apk_extractors/apk_signature.py`

**Key androguard API calls:**
```python
# Get certificate objects
certs = self.apk.get_certificates()     # Returns list of asn1crypto Certificate objects

# For each certificate:
cert.subject.human_friendly              # Subject DN
cert.issuer.human_friendly               # Issuer DN
cert.serial_number                       # Serial
cert.not_valid_before                    # datetime
cert.not_valid_after                     # datetime
cert.hash_algo                           # e.g., "sha256"
cert.signature_algo                      # e.g., "rsassa_pkcs1v15"

# SHA-1 thumbprint
import hashlib
hashlib.sha1(cert.dump()).hexdigest()

# SHA-256 thumbprint
hashlib.sha256(cert.dump()).hexdigest()

# Self-signed check
cert.subject == cert.issuer

# Signature scheme detection:
# v1: Check META-INF/*.SF and META-INF/*.RSA/DSA/EC files exist
# v2/v3: androguard >= 4.x has is_signed_v2() / is_signed_v3()
self.apk.is_signed_v1()
self.apk.is_signed_v2()
self.apk.is_signed_v3()
```

**Implementation notes:**
- Mirror the structure of `PECodeSigningInfo` / `MachOCodeSigningInfo`
- The `_id` field should be `self.sha256` (same as PE/Mach-O signature extractors)

### 6.5 APKDexExtractor

**File:** `redb/extractors/apk_extractors/apk_dex.py`

This is the most complex extractor. Use `androguard.core.dex` for DEX parsing.

**Key androguard API calls:**
```python
from androguard.core.dex import DEX

# Get raw DEX data from APK
dex_files = self.apk.get_all_dex()  # Returns list of raw DEX bytes

for dex_name, dex_data in zip(self.apk.get_dex_names(), dex_files):
    d = DEX(dex_data)

    # Class enumeration
    classes = d.get_classes()
    for cls in classes:
        cls.get_name()          # e.g., "Lcom/example/MainActivity;"

    # Method enumeration
    methods = d.get_methods()
    for method in methods:
        method.get_class_name()  # e.g., "Lcom/example/MainActivity;"
        method.get_name()        # e.g., "onCreate"
        method.get_descriptor()  # e.g., "(Landroid/os/Bundle;)V"

    # String constants
    strings = d.get_strings()    # Returns list of string constants
```

**Computing `top_packages`:**
```python
from collections import Counter

package_counter = Counter()
for cls in classes:
    name = cls.get_name()  # "Lcom/example/foo/Bar;"
    # Convert to package: "com.example.foo"
    parts = name[1:].replace("/", ".").rsplit(".", 1)
    if len(parts) > 1:
        package = parts[0]
    else:
        package = "(default)"
    package_counter[package] += 1

top_packages = [
    {"package": pkg, "class_count": count}
    for pkg, count in package_counter.most_common(20)
]
```

**Computing `api_usage`:**
Iterate over all method cross-references (xrefs) or method invocations. For each invoked method, check if it matches any sensitive API pattern. See Section 12 for the full categorization reference.

```python
api_usage = {cat: [] for cat in SENSITIVE_API_CATEGORIES}

for method in d.get_methods():
    # Get the bytecode and look for invoke-* instructions
    code = method.get_code()
    if not code:
        continue
    # Use androguard's analysis or instruction iteration
    # to find method references that match sensitive patterns
```

**Computing `obfuscation_indicators`:**
```python
class_names = [cls.get_name() for cls in classes]
method_names = [m.get_name() for m in methods if m.get_name() not in ("<init>", "<clinit>")]

short_class = sum(1 for n in class_names if len(n.split("/")[-1].rstrip(";")) <= 2)
short_method = sum(1 for n in method_names if len(n) <= 2)

obfuscation_indicators = {
    "short_class_names_pct": round(short_class / max(len(class_names), 1), 4),
    "short_method_names_pct": round(short_method / max(len(method_names), 1), 4),
    "non_ascii_identifiers": sum(1 for n in class_names if not n.isascii()),
    "avg_class_name_length": round(
        sum(len(n) for n in class_names) / max(len(class_names), 1), 2
    ),
}
```

**ClickHouse export:**
- `redb_apk_dex`: One row per DEX file — `sha256`, `dex_sha256`, `dex_filename`, `class_count`, `method_count`, `string_count`, `top_packages` (JSON string), `obfuscation_indicators` (JSON string), `analysis_date`
- `redb_apk_dex_api_usage`: One row per API category per DEX — `sha256`, `dex_sha256`, `category`, `api_calls` (Array(String)), `analysis_date`

### 6.6 APKResourceExtractor

**File:** `redb/extractors/apk_extractors/apk_resources.py`

**Implementation approach:**
```python
import hashlib
from magika import Magika

magika = Magika()

resources = []
suspicious_files = []

zf = self._get_zip_file()
if zf:
    with zf:
        for info in zf.infolist():
            if info.is_dir():
                continue
            # Only scan res/ and assets/ directories
            if not (info.filename.startswith("res/") or
                    info.filename.startswith("assets/")):
                continue

            data = zf.read(info.filename)
            file_sha256 = hashlib.sha256(data).hexdigest()
            filetype = magika.identify_bytes(data).output.label

            resource = APKResource(
                path=info.filename,
                size=info.file_size,
                sha256=file_sha256,
                filetype_magika=filetype,
            )

            # Flag suspicious file types
            SUSPICIOUS_TYPES = {
                "elf", "pebin", "dex", "apk", "zip", "shell",
                "javascript", "python", "powershell", "batch",
            }
            if filetype in SUSPICIOUS_TYPES:
                resource.is_suspicious = True
                suspicious_files.append(resource)

            resources.append(resource)
```

**ClickHouse export:** One row per resource in `redb_apk_resources`:
- `sha256`, `resource_path`, `resource_size`, `resource_sha256`, `filetype_magika`, `is_suspicious`, `analysis_date`

**Performance note:** For APKs with very large resource directories (some apps have 10K+ files in `res/`), consider limiting to the top N resources by size or only scanning `assets/` fully while sampling `res/`. Document any limits applied.

### 6.7 APKNativeLibExtractor

**File:** `redb/extractors/apk_extractors/apk_native_libs.py`

**Implementation approach:**
```python
native_libs = []
abis = set()

zf = self._get_zip_file()
if zf:
    with zf:
        for info in zf.infolist():
            if info.filename.startswith("lib/") and info.filename.endswith(".so"):
                parts = info.filename.split("/")
                if len(parts) >= 3:
                    abi = parts[1]
                    filename = parts[-1]
                    abis.add(abi)

                    data = zf.read(info.filename)
                    lib_sha256 = hashlib.sha256(data).hexdigest()

                    native_libs.append(APKNativeLib(
                        abi=abi,
                        filename=filename,
                        size=info.file_size,
                        sha256=lib_sha256,
                        is_known_packer=filename in KNOWN_PACKER_LIBS,
                    ))
```

See Section 11 for the `KNOWN_PACKER_LIBS` reference list.

### 6.8 APKInconsistencyTestsExtractor

**File:** `redb/extractors/apk_extractors/apk_inconsistency_tests.py`

Each test is a private method returning `bool`:

```python
def _test_zip_bomb(self):
    """Check if any ZIP entry has compression ratio > 100:1."""
    zf = self._get_zip_file()
    if not zf:
        return None
    with zf:
        for info in zf.infolist():
            if info.compress_size > 0:
                ratio = info.file_size / info.compress_size
                if ratio > 100:
                    return True
    return False

def _test_zip_duplicate_entries(self):
    """Check for duplicate filenames in ZIP directory."""
    zf = self._get_zip_file()
    if not zf:
        return None
    with zf:
        names = [info.filename for info in zf.infolist()]
        return len(names) != len(set(names))

def _test_zip_path_traversal(self):
    """Check for path traversal (../) in ZIP entry names."""
    for f in self._list_files():
        if ".." in f or f.startswith("/"):
            return True
    return False

def _test_zip_suspicious_timestamps(self):
    """Check for timestamps at epoch (1980) or in the future."""
    zf = self._get_zip_file()
    if not zf:
        return None
    now = datetime.now()
    with zf:
        for info in zf.infolist():
            try:
                dt = datetime(*info.date_time)
                if dt.year <= 1980 or dt > now:
                    return True
            except (ValueError, TypeError):
                continue
    return False

def _test_hidden_dex_files(self):
    """Check for DEX files not matching classes*.dex pattern."""
    import re
    standard_pattern = re.compile(r"^classes\d*\.dex$")
    for f in self._list_files():
        if f.endswith(".dex") and not standard_pattern.match(f.split("/")[-1]):
            return True
    return False

def _test_emulator_detection_strings(self):
    """Check for emulator detection patterns in DEX strings."""
    # Inspect DEX strings for known emulator detection indicators
    EMULATOR_INDICATORS = {
        "generic", "sdk", "google_sdk", "Emulator",
        "goldfish", "ranchu", "Andy", "Genymotion",
        "BlueStacks", "nox", "ttVM_Hdragon",
    }
    # Use androguard to extract strings from DEX, then check
    ...

def _test_debugger_detection(self):
    """Check for debugger detection API calls in DEX."""
    # Look for: Debug.isDebuggerConnected, Debug.waitingForDebugger
    ...

def _test_root_detection(self):
    """Check for root detection patterns in DEX."""
    ROOT_INDICATORS = {
        "/system/app/Superuser.apk",
        "/system/xbin/su",
        "/system/bin/su",
        "com.noshufou.android.su",
        "com.thirdparty.superuser",
        "eu.chainfire.supersu",
        "com.koushikdutta.superuser",
        "com.topjohnwu.magisk",
    }
    ...
```

---

## 7. Ingestor Integration

**File:** `redb/ingestor.py`

Replace the stub at line 1668:

```python
elif filetype == "apk":
    logger.debug("APK file detected")
```

With the full dispatch block:

```python
elif filetype == "apk":
    logger.debug("APK file detected")

    # Import APK extractors
    from redb.extractors.apk_extractor import APKExtractor
    from redb.extractors.apk_extractors.apk_features import APKFeaturesExtractor
    from redb.extractors.apk_extractors.apk_manifest import APKManifestExtractor
    from redb.extractors.apk_extractors.apk_permissions import APKPermissionsExtractor
    from redb.extractors.apk_extractors.apk_signature import APKSignatureExtractor
    from redb.extractors.apk_extractors.apk_dex import APKDexExtractor
    from redb.extractors.apk_extractors.apk_resources import APKResourceExtractor
    from redb.extractors.apk_extractors.apk_native_libs import APKNativeLibExtractor
    from redb.extractors.apk_extractors.apk_inconsistency_tests import APKInconsistencyTestsExtractor

    apk_modules = [
        APKFeaturesExtractor,
        APKManifestExtractor,
        APKPermissionsExtractor,
        APKSignatureExtractor,
        APKDexExtractor,
        APKResourceExtractor,
        APKNativeLibExtractor,
        APKInconsistencyTestsExtractor,
    ]

    # Parse APK once with androguard, share across all extractors
    try:
        from androguard.core.apk import APK
        apk = APK(filepath)
    except Exception as e:
        logger.error(f"Failed to parse APK {filepath}: {e}")
        apk = None

    # Run format-agnostic extractors first (same as PE/ELF/MachO)
    # DIE
    if 'all' in selected_modules or 'DIEExtractor' in selected_modules:
        try:
            extractor = DIEExtractor(
                filepath, logger, exporters=exporters,
                index_prefix=index_prefix
            )
            result = extractor.export_data()
            is_packed = bool(result) if result is not None else None
            if result:
                results[ImportResult.CORRECTLY] += 1
            elif result is False:
                results[ImportResult.FAILED] += 1
        except Exception as e:
            logger.error(f"Error in DIEExtractor: {str(e)}")
            results[ImportResult.FAILED] += 1

    # BasicProperties
    if 'all' in selected_modules or 'BasicPropertiesExtractor' in selected_modules:
        try:
            extractor = BasicPropertiesExtractor(
                filepath, logger, exporters=exporters,
                index_prefix=index_prefix
            )
            if is_packed is not None:
                extractor.is_packed = is_packed
            result = extractor.export_data()
            if result:
                results[ImportResult.CORRECTLY] += 1
            elif result is False:
                results[ImportResult.FAILED] += 1
        except Exception as e:
            logger.error(f"Error in BasicPropertiesExtractor: {str(e)}")
            results[ImportResult.FAILED] += 1

    # Hashes
    if 'all' in selected_modules or 'HashExtractor' in selected_modules:
        try:
            extractor = HashExtractor(
                filepath, logger, exporters=exporters,
                index_prefix=index_prefix
            )
            result = extractor.export_data()
            if result:
                results[ImportResult.CORRECTLY] += 1
            elif result is False:
                results[ImportResult.FAILED] += 1
        except Exception as e:
            logger.error(f"Error in HashExtractor: {str(e)}")
            results[ImportResult.FAILED] += 1

    # YARA
    if 'all' in selected_modules or 'YaraExtractor' in selected_modules:
        try:
            extractor = YaraExtractor(
                filepath, logger, exporters=exporters,
                index_prefix=index_prefix
            )
            result = extractor.export_data()
            if result:
                results[ImportResult.CORRECTLY] += 1
            elif result is False:
                results[ImportResult.FAILED] += 1
        except Exception as e:
            logger.error(f"Error in YaraExtractor: {str(e)}")
            results[ImportResult.FAILED] += 1

    # APK-specific extractors
    for module in apk_modules:
        if 'all' in selected_modules or module.__name__ in selected_modules:
            try:
                logger.debug(f"Running {module.__name__}")
                extractor = module(
                    filepath,
                    logger,
                    exporters=exporters,
                    index_prefix=index_prefix,
                    apk=apk
                )
                result = extractor.export_data()
                if result:
                    results[ImportResult.CORRECTLY] += 1
                elif result is False:
                    results[ImportResult.FAILED] += 1
            except Exception as e:
                logger.error(f"Error in {module.__name__}: {str(e)}")
                results[ImportResult.FAILED] += 1
```

**Note:** Follow the exact error-handling and `selected_modules` check pattern used by the existing PE/ELF/Mach-O dispatch blocks. The code above mirrors the pattern from `ingestor.py:1540-1666`.

---

## 8. Hashes Dataclass Update

**File:** `redb/models/dataclasses.py`

Add to the `Hashes` dataclass after the existing Mach-O hashes:

```python
@dataclass
class Hashes:
    md5: str
    sha1: str
    sha256: str
    ssdeep_hash: str
    tlsh_hash: str
    authentihash: Optional[str] = None  # PE
    imphash: Optional[str] = None  # PE
    impfuzzy: Optional[str] = None  # PE TODO: implement
    typerefhash: Optional[str] = None  # DotNet
    richhash: Optional[str] = None  # PE
    richpe_hash: Optional[str] = None  # PE
    richpv_hash: Optional[str] = None  # PE
    richpv_hash_sorted: Optional[str] = None  # PE
    import_hash: Optional[str] = None  # ELF
    export_hash: Optional[str] = None  # ELF
    section_hash: Optional[str] = None  # ELF
    symbol_hash: Optional[str] = None  # ELF (symhash)
    dynamic_hash: Optional[str] = None  # ELF
    # Mach-O similarity hashes
    macho_dylib_hash: Optional[str] = None
    macho_import_hash: Optional[str] = None
    macho_export_hash: Optional[str] = None
    macho_entitlement_hash: Optional[str] = None
    macho_symhash: Optional[str] = None
    # APK similarity hashes
    permhash: Optional[str] = None  # APK: SHA-256 of sorted permissions (Mandiant/Google)
```

The `permhash` should be computed in `HashExtractor` when the filetype is APK, using the `permhash` library:

```python
# In HashExtractor, when filetype == "apk":
import permhash as permhash_lib
self.hashes.permhash = permhash_lib.permhash_apk(self.filepath)
```

The `permhash` column must be added to the existing `redb_hashes` table:

```sql
ALTER TABLE redb_hashes
    ADD COLUMN IF NOT EXISTS permhash Nullable(FixedString(64));
```

---

## 9. ClickHouse Schema

Create the following tables. Naming convention follows existing tables (`redb_pe_features`, `redb_elf_features`, etc.):

```sql
-- Core metadata (one row per APK)
CREATE TABLE redb_apk_features (
    sha256              FixedString(64),
    md5                 FixedString(32),
    sha1                FixedString(40),
    package_name        String,
    app_name            String,
    version_code        UInt32,
    version_name        String,
    min_sdk_version     Nullable(UInt16),
    target_sdk_version  Nullable(UInt16),
    compile_sdk_version Nullable(UInt16),
    main_activity       Nullable(String),
    is_debuggable       UInt8,
    allow_backup        UInt8,
    uses_cleartext_traffic UInt8,
    supported_abis      Array(String),
    dex_count           UInt16,
    total_dex_size      UInt64,
    total_file_count    UInt32,
    has_native_code     UInt8,
    has_assets          UInt8,
    uses_libraries      Array(String),
    earliest_content_modification Nullable(String),
    latest_content_modification   Nullable(String),
    contains_embedded_apk UInt8,
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY sha256;

-- Manifest components (one row per component)
CREATE TABLE redb_apk_components (
    sha256              FixedString(64),
    component_type      LowCardinality(String),  -- "activity", "service", "receiver", "provider"
    class_name          String,
    is_exported         UInt8,
    intent_actions      Array(String),
    intent_categories   Array(String),
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY (sha256, component_type, class_name);

-- Manifest summary (one row per APK)
CREATE TABLE redb_apk_manifest (
    sha256              FixedString(64),
    md5                 FixedString(32),
    sha1                FixedString(40),
    activity_count      UInt16,
    service_count       UInt16,
    receiver_count      UInt16,
    provider_count      UInt16,
    intent_filters_by_action   Array(String),
    intent_filters_by_category Array(String),
    uses_features       Array(String),
    manifest_xml        Nullable(String),
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY sha256;

-- Permissions (one row per permission per APK)
CREATE TABLE redb_apk_permissions (
    sha256              FixedString(64),
    permission_name     String,
    protection_level    LowCardinality(String),
    is_custom           UInt8,
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY (sha256, permission_name);

-- Signing info (one row per APK)
CREATE TABLE redb_apk_signature (
    sha256              FixedString(64),
    md5                 FixedString(32),
    sha1                FixedString(40),
    is_signed           UInt8,
    signature_scheme_versions Array(UInt8),
    number_of_certificates UInt8,
    signer_subject      Nullable(String),
    signer_issuer       Nullable(String),
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY sha256;

-- Certificate details (one row per certificate per APK)
CREATE TABLE redb_apk_certificates (
    sha256              FixedString(64),
    subject             String,
    issuer              String,
    serial_number       String,
    valid_from          String,
    valid_to            String,
    thumbprint_sha1     FixedString(40),
    thumbprint_sha256   FixedString(64),
    algorithm           Nullable(String),
    key_size            Nullable(UInt16),
    is_self_signed      UInt8,
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY (sha256, thumbprint_sha256);

-- DEX file analysis (one row per DEX file)
CREATE TABLE redb_apk_dex (
    sha256              FixedString(64),
    dex_sha256          FixedString(64),
    dex_filename        String,
    dex_tlsh            Nullable(String),
    class_count         UInt32,
    method_count        UInt32,
    string_count        UInt32,
    top_packages        String,       -- JSON
    obfuscation_indicators String,    -- JSON
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY (sha256, dex_sha256);

-- DEX API usage (one row per category per DEX)
CREATE TABLE redb_apk_dex_api_usage (
    sha256              FixedString(64),
    dex_sha256          FixedString(64),
    category            LowCardinality(String),
    api_calls           Array(String),
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY (sha256, dex_sha256, category);

-- Resource inventory (one row per resource)
CREATE TABLE redb_apk_resources (
    sha256              FixedString(64),
    resource_path       String,
    resource_size       UInt64,
    resource_sha256     FixedString(64),
    filetype_magika     LowCardinality(String),
    is_suspicious       UInt8,
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY (sha256, resource_path);

-- Native libraries (one row per .so file)
CREATE TABLE redb_apk_native_libs (
    sha256              FixedString(64),
    abi                 LowCardinality(String),
    filename            String,
    size                UInt64,
    lib_sha256          FixedString(64),
    is_known_packer     UInt8,
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY (sha256, abi, filename);

-- Inconsistency tests (one row per APK)
CREATE TABLE redb_apk_inconsistency_tests (
    sha256              FixedString(64),
    md5                 FixedString(32),
    sha1                FixedString(40),
    test_zip_bomb                    Nullable(UInt8),
    test_zip_duplicate_entries       Nullable(UInt8),
    test_zip_path_traversal          Nullable(UInt8),
    test_zip_suspicious_timestamps   Nullable(UInt8),
    test_hidden_dex_files            Nullable(UInt8),
    test_manifest_component_mismatch Nullable(UInt8),
    test_debuggable_release          Nullable(UInt8),
    test_emulator_detection_strings  Nullable(UInt8),
    test_debugger_detection          Nullable(UInt8),
    test_root_detection              Nullable(UInt8),
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY sha256;
```

---

## 10. Androguard API Reference

Quick reference for the most commonly used androguard APIs. Full docs: https://androguard.readthedocs.io/

### APK class (`androguard.core.apk.APK`)

| Method | Returns | Description |
|--------|---------|-------------|
| `APK(filepath)` | `APK` | Parse an APK file |
| `.is_valid_APK()` | `bool` | Check if parsing succeeded |
| `.get_package()` | `str` | Package name |
| `.get_app_name()` | `str` | Application display name |
| `.get_androidversion_code()` | `str` | Version code |
| `.get_androidversion_name()` | `str` | Version name |
| `.get_min_sdk_version()` | `str` | Minimum SDK |
| `.get_target_sdk_version()` | `str` | Target SDK |
| `.get_main_activity()` | `str` | Main/launcher activity |
| `.get_activities()` | `list[str]` | All activity class names |
| `.get_services()` | `list[str]` | All service class names |
| `.get_receivers()` | `list[str]` | All receiver class names |
| `.get_providers()` | `list[str]` | All provider class names |
| `.get_permissions()` | `list[str]` | Requested permissions |
| `.get_declared_permissions()` | `list[str]` | Custom-defined permissions |
| `.get_features()` | `list[str]` | Uses-feature declarations |
| `.get_libraries()` | `list[str]` | Uses-library declarations |
| `.get_files()` | `list[str]` | All files in the APK |
| `.get_certificates()` | `list[Certificate]` | X.509 certificate objects |
| `.get_all_dex()` | `list[bytes]` | Raw DEX file contents |
| `.get_dex_names()` | `list[str]` | DEX filenames |
| `.is_signed_v1()` | `bool` | JAR signature present |
| `.is_signed_v2()` | `bool` | v2 signature present |
| `.is_signed_v3()` | `bool` | v3 signature present |
| `.get_attribute_value(tag, attr)` | `str` | Get manifest attribute |
| `.get_android_manifest_xml()` | `minidom` | Parsed manifest XML |
| `.get_intent_filters(type, name)` | `dict` | Intent filters for component |

### DEX class (`androguard.core.dex.DEX`)

| Method | Returns | Description |
|--------|---------|-------------|
| `DEX(raw_bytes)` | `DEX` | Parse raw DEX data |
| `.get_classes()` | `list[ClassDefItem]` | All class definitions |
| `.get_methods()` | `list[EncodedMethod]` | All methods |
| `.get_strings()` | `list[str]` | All string constants |

---

## 11. Known Packer/Protector Signatures

Native library names commonly associated with packers and protectors. Used by `APKNativeLibExtractor` to flag `is_known_packer`:

```python
KNOWN_PACKER_LIBS = {
    # Jiagu (360/Qihoo)
    "libjiagu.so", "libjiagu_a64.so", "libjiagu_x86.so", "libjiagu_x64.so",
    # Bangcle/SecNeo
    "libsecexe.so", "libsecmain.so", "libSecShell.so",
    # Baidu
    "libbaiduprotect.so",
    # Tencent (Legu)
    "libshell-super.2019.so", "libshella-*.so", "libtxAppProtect.so",
    "libBugly.so", "mix.dex",
    # iJiami
    "libexec.so", "libexecmain.so",
    # Alibaba
    "libmobisec.so", "libaliprotect.so",
    # APKProtect
    "libAPKProtect.so",
    # Pangxie (Pangolin)
    "libdexjni.so",
    # DexProtector
    "libdexprotector.so",
    # AppSolid
    "libAppSolid.so",
    # Kiwisec
    "libkwscmm.so",
    # DingXiang
    "libx3g.so",
    # NQ Shield
    "libnqshield.so",
    # Generic / other
    "libprotectClass.so",
    "libDexHelper.so",
    "libdexloader.so",
    "libfdog.so",
}
```

**Note:** This list should be maintained and expanded over time. For glob-style matching (e.g., `libshella-*.so`), use `fnmatch` instead of exact set lookup.

---

## 12. Sensitive API Categorization Reference

Used by `APKDexExtractor` to categorize API calls. Each category maps to a list of class/method patterns:

```python
SENSITIVE_API_CATEGORIES = {
    "reflection": [
        "Ljava/lang/reflect/Method;->invoke",
        "Ljava/lang/reflect/Field;->get",
        "Ljava/lang/reflect/Field;->set",
        "Ljava/lang/reflect/Constructor;->newInstance",
        "Ljava/lang/Class;->forName",
        "Ljava/lang/Class;->getMethod",
        "Ljava/lang/Class;->getDeclaredMethod",
        "Ljava/lang/Class;->getDeclaredField",
        "Ljava/lang/ClassLoader;->loadClass",
    ],
    "crypto": [
        "Ljavax/crypto/Cipher;->getInstance",
        "Ljavax/crypto/Cipher;->init",
        "Ljavax/crypto/spec/SecretKeySpec;-><init>",
        "Ljavax/crypto/spec/IvParameterSpec;-><init>",
        "Ljava/security/MessageDigest;->getInstance",
        "Ljava/security/KeyStore;->getInstance",
        "Ljavax/crypto/Mac;->getInstance",
    ],
    "dynamic_loading": [
        "Ldalvik/system/DexClassLoader;-><init>",
        "Ldalvik/system/PathClassLoader;-><init>",
        "Ldalvik/system/InMemoryDexClassLoader;-><init>",
        "Ldalvik/system/BaseDexClassLoader;-><init>",
        "Ljava/lang/Runtime;->exec",
        "Ljava/lang/ProcessBuilder;->start",
    ],
    "telephony": [
        "Landroid/telephony/TelephonyManager;->getDeviceId",
        "Landroid/telephony/TelephonyManager;->getSubscriberId",
        "Landroid/telephony/TelephonyManager;->getLine1Number",
        "Landroid/telephony/TelephonyManager;->getSimSerialNumber",
        "Landroid/telephony/TelephonyManager;->getNetworkOperator",
        "Landroid/telephony/TelephonyManager;->getSimOperator",
    ],
    "sms": [
        "Landroid/telephony/SmsManager;->sendTextMessage",
        "Landroid/telephony/SmsManager;->sendMultipartTextMessage",
        "Landroid/telephony/SmsManager;->sendDataMessage",
    ],
    "network": [
        "Ljava/net/HttpURLConnection;->connect",
        "Ljava/net/URL;->openConnection",
        "Lokhttp3/OkHttpClient;-><init>",
        "Lokhttp3/Request$Builder;->build",
        "Lorg/apache/http/client/HttpClient;->execute",
        "Landroid/webkit/WebView;->loadUrl",
        "Landroid/webkit/WebView;->setWebViewClient",
    ],
    "native": [
        "Ljava/lang/System;->loadLibrary",
        "Ljava/lang/System;->load",
        "Ljava/lang/Runtime;->loadLibrary",
    ],
    "device_info": [
        "Landroid/os/Build;->FINGERPRINT",
        "Landroid/os/Build;->MODEL",
        "Landroid/os/Build;->MANUFACTURER",
        "Landroid/os/Build;->PRODUCT",
        "Landroid/os/Build;->BRAND",
        "Landroid/os/Build;->DEVICE",
        "Landroid/os/Build;->HARDWARE",
        "Landroid/os/Build;->SERIAL",
        "Landroid/os/Build$VERSION;->SDK_INT",
        "Landroid/provider/Settings$Secure;->getString",  # ANDROID_ID
    ],
    "file_io": [
        "Ljava/io/FileOutputStream;-><init>",
        "Ljava/io/FileInputStream;-><init>",
        "Landroid/content/SharedPreferences;->edit",
        "Landroid/database/sqlite/SQLiteDatabase;->execSQL",
        "Landroid/database/sqlite/SQLiteDatabase;->rawQuery",
    ],
    "ipc": [
        "Landroid/content/ContentResolver;->query",
        "Landroid/content/ContentResolver;->insert",
        "Landroid/content/ContentResolver;->delete",
        "Landroid/content/Intent;-><init>",
        "Landroid/content/Context;->sendBroadcast",
        "Landroid/content/Context;->startService",
        "Landroid/content/Context;->bindService",
    ],
}
```

**Matching approach:** For each method invocation found in DEX bytecode, check if its full signature (class + method) starts with any of the patterns above. Store only the first match per unique API call (avoid duplicates from multiple call sites).

---

## Implementation Checklist

- [ ] Add `androguard` and `permhash` to `requirements.txt`
- [ ] Create `redb/extractors/apk_extractor.py` (base class)
- [ ] Create `redb/extractors/apk_extractors/__init__.py`
- [ ] Implement `APKFeaturesExtractor`
- [ ] Implement `APKManifestExtractor`
- [ ] Implement `APKPermissionsExtractor`
- [ ] Implement `APKSignatureExtractor`
- [ ] Implement `APKDexExtractor`
- [ ] Implement `APKResourceExtractor`
- [ ] Implement `APKNativeLibExtractor`
- [ ] Implement `APKInconsistencyTestsExtractor`
- [ ] Add APK tags to `redb/extractors/enum.py`
- [ ] Add APK dataclasses to `redb/models/dataclasses.py`
- [ ] Add `permhash` field to `Hashes` dataclass
- [ ] Wire up APK dispatch in `redb/ingestor.py`
- [ ] Integrate `permhash` computation in `HashExtractor`
- [ ] Create ClickHouse migration scripts for new tables
- [ ] Unit tests per extractor
- [ ] Integration test: full APK ingestion pipeline
- [ ] Cross-validate output against VirusTotal for reference samples