关于repo
repo只是谷歌做的,方便下载安卓源码的工具,本质上是对下载清单进行批量处理,然后使用git克隆。
 在windows上下载源码只需要自己处理即可。
具体做法
首先使用git克隆安卓源码清单
git clone https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest
随后进入manifest目录,查看所有tag
git tag

tag名就是安卓源码的版本,选择你要的版本,记下来。例如android-13.0.0_r9
 随后切换分支
git checkout android-13.0.0_r9

 记住文件夹中的default.xml的路径
 以上操作完成了清单的下载,接下来我们只需要执行按清单下载的操作即可。
 我提供两个我编写的脚本,一个python环境,一个golang环境。
 注意:该脚本不支持断点续传,如需使用,请保持网络环境良好或自行修改脚本。
Python环境
该Python下载脚本仅支持单线程下载,不过git仍可以跑满你的网速
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
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
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的脚本推荐大家不要乱用,过多的下载进程会对镜像站造成巨大的负载
 



















