Windows下载AOSP

关于repo

repo只是谷歌做的,方便下载安卓源码的工具,本质上是对下载清单进行批量处理,然后使用git克隆。

在windows上下载源码只需要自己处理即可。

具体做法

首先使用git克隆安卓源码清单

shell 复制代码
git clone https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest

随后进入manifest目录,查看所有tag

shell 复制代码
git tag

tag名就是安卓源码的版本,选择你要的版本,记下来。例如android-13.0.0_r9

随后切换分支

shell 复制代码
git checkout android-13.0.0_r9

记住文件夹中的default.xml的路径

以上操作完成了清单的下载,接下来我们只需要执行按清单下载的操作即可。

我提供两个我编写的脚本,一个python环境,一个golang环境。
注意:该脚本不支持断点续传,如需使用,请保持网络环境良好或自行修改脚本。

Python环境

该Python下载脚本仅支持单线程下载,不过git仍可以跑满你的网速

python3 复制代码
import xml.dom.minidom
import os
from subprocess import call

version = "android-13.0.0_r9"

# 1. 源码要保存的路径
rootdir = "D:/AOSP/"+version

# 2. git 的路径
git = r"C:\Program Files\Git\cmd\git.exe"

# 3. default.xml 的路径
dom = xml.dom.minidom.parse(r"D:\AOSP\manifest\default.xml")
root = dom.documentElement

# 4. 只支持单一镜像源
prefix = git + " clone https://aosp.tuna.tsinghua.edu.cn/"
suffix = ".git"

if __name__ == '__main__':

    if not os.path.exists(rootdir):
        os.mkdir(rootdir)

    for node in root.getElementsByTagName("project"):
        os.chdir(rootdir)
        d = node.getAttribute("path")
        last = d.rfind("/")
        if last != -1:
            d = rootdir + "/" + d[:last]
            if not os.path.exists(d):
                os.makedirs(d)
            os.chdir(d)
        cmd = prefix + node.getAttribute("name") + suffix
        # 单线程下载
        call(cmd)

Golang环境

该golang脚本支持从多个镜像站并发下载,可限制每个镜像站同时下载的线程个数,以及总线程个数。
注意: * 总线程个数应小于等于各个镜像站线程个数相加*
resource.go

go 复制代码
package main

import (
	"sync"
)

type Resource struct {
	Url  string
	Lock chan struct{}
}

type ResourcePool struct {
	resources []*Resource
	cond      *sync.Cond
}

func NewResourcePool(list []*Resource) *ResourcePool {
	pool := &ResourcePool{
		cond: sync.NewCond(&sync.Mutex{}),
	}
	pool.resources = list

	return pool
}

func (pool ResourcePool) GetResource() *Resource {
	pool.cond.L.Lock()
	defer pool.cond.L.Unlock()

	for {
		for _, resource := range pool.resources {
			select {
			case resource.Lock <- struct{}{}:
				return resource
			default:
				continue
			}
		}

		pool.cond.Wait()
	}
}

func (pool ResourcePool) ReleaseResource(resource *Resource) {
	<-resource.Lock

	pool.cond.Signal()
}

main.go

go 复制代码
package main

import (
	"encoding/xml"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
)

type Project struct {
	XMLName xml.Name `xml:"project"`
	Name    string   `xml:"name,attr"`
	Path    string   `xml:"path,attr"`
}

type Manifest struct {
	XMLName xml.Name  `xml:"manifest"`
	Project []Project `xml:"project"`
}

var (
	concurrentNum int
	rootDir       string
	manifestPath  string

	wg sync.WaitGroup
)

var resourceA = &Resource{Url: "https://mirrors.bfsu.edu.cn/git/AOSP/%s.git", Lock: make(chan struct{}, 4)}
var resourceB = &Resource{Url: "https://aosp.tuna.tsinghua.edu.cn/%s.git", Lock: make(chan struct{}, 3)}

//var resourceC = &Resource{Url: "https://mirror.nju.edu.cn/%s.git", Lock: make(chan struct{}, 3)}

//var resourceC = &Resource{Url: "https://mirrors.shanghaitech.edu.cn/%s.git", Lock: make(chan struct{}, 3)}

func init() {
	flag.IntVar(&concurrentNum, "concurrentNum", 7, "Number of concurrent goroutines")
	flag.StringVar(&rootDir, "root", "D:/AOSP/android-13.0.0_r9", "Root dir of AOSP.")
	flag.StringVar(&manifestPath, "manifest", "D:/AOSP/manifest/default.xml", "Manifest of AOSP.")
}

func errorHandle(str string, err error) {
	if err != nil {
		log.Fatalf("Failed to %s: %v", str, err)
		os.Exit(-6)
	}
}

func main() {
	flag.Parse()
	manifestXML, err := os.ReadFile(manifestPath)
	errorHandle("Read manifest file", err)

	var manifest Manifest
	err = xml.Unmarshal(manifestXML, &manifest)
	errorHandle("Parse manifest XML", err)

	err = os.MkdirAll(rootDir, 0755)
	errorHandle("Create root directory", err)

	sem := make(chan struct{}, concurrentNum)

	pool := NewResourcePool([]*Resource{
		resourceA, resourceB,
	})

	for _, node := range manifest.Project {
		wg.Add(1)
		go func(project Project) {
			defer wg.Done()
			sem <- struct{}{}
			defer func() { <-sem }()

			cmdDir := rootDir

			d := project.Path
			last := strings.LastIndex(d, "/")
			if last != -1 {
				d = filepath.Join(rootDir, d[:last])
				if err := os.MkdirAll(d, 0755); err != nil {
					errorHandle("Create d directory", err)
				}

				cmdDir = d
			}
			resource := pool.GetResource()
			if resource == nil {
				fmt.Println("No resource available")
				os.Exit(2)
				return
			}

			cmd := exec.Command("git", "clone", fmt.Sprintf(resource.Url, project.Name))
			cmdDir = strings.ReplaceAll(cmdDir+"\\", "/", "\\")
			cmd.Dir = cmdDir
			if err := cmd.Run(); err != nil {
				fmt.Printf("Failed to clone node: %v %s \n", err, cmd)
				return
			}
			pool.ReleaseResource(resource)

			fmt.Printf("Cloned node: %s \n", project.Name)
		}(node)
	}

	wg.Wait()
}

截至到23年10月3日,完全可用的镜像站仅剩清华,其他AOSP的镜像或多或少均有问题

python的脚本足矣,经测试,均速16m/s,一晚上可以下载好android-13.0.0_r9的所有源码

go的脚本推荐大家不要乱用,过多的下载进程会对镜像站造成巨大的负载

相关推荐
David爱编程10 分钟前
Java 三目运算符完全指南:写法、坑点与最佳实践
java·后端
遇见尚硅谷18 分钟前
C语言:单链表学习
java·c语言·学习
学习编程的小羊1 小时前
Spring Boot 全局异常处理与日志监控实战
java·spring boot·后端
CV资深专家1 小时前
Launcher3启动
android
YA3332 小时前
java基础(六)jvm
java·开发语言
stevenzqzq2 小时前
glide缓存策略和缓存命中
android·缓存·glide
雅雅姐2 小时前
Android 16 的用户和用户组定义
android
没有了遇见2 小时前
Android ConstraintLayout 之ConstraintSet
android
JavaArchJourney2 小时前
Java 集合框架
java
尘民10243 小时前
面试官笑了:线程start() 为什么不能再来一次?
java